I'm having issues with initializing certain structs which are declared as static in my library header
Header file:
struct game_setting
{
uint8_t parameter;
uint8_t alternatives[6];
uint8_t alternatives_number;
};
static game_setting game_status;
init-function in .c-file:
void menu_init()
{
static uint8_t game_parameters_array[6];
static game_setting game_status = {&game_parameters_array[RUN_STATUS],{OFF,ON},2}
Which returns 'Initializer element is not computable at load time'
I'm looking for an efficient way of assigning values to the static struct, what is wrong?
Main script
#define F_CPU 4915200UL
#define OFFSET 0x2000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include "SPI.h"
#include "MCP2515.h"
#include "MCP2515_Commands.h"
#include "adc.h"
#include "multiboard.h"
#include "OLED.h"
#include "OLED_menu.h"
#include "CAN.h"
#include "USART.h"
#define SPI_DEBUG
#define CAN_MESSAGE_DEBUG
#define UPDATEMESSAGES 255
// Define baud rate
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
int main(void){
FILE fileHandle = USART_Init();
init_xMem();
stdout = &fileHandle;
stdin = &fileHandle;
printf("start of init\n\r");
menu_init();
printf("menu_init completed\n");
OLED_init();
CAN_init();
ADCInit();
initController();
can_message msg;
msg.id = 1;
controller C;
int i = 1;
while (1) {
menu_page_print_data();
_delay_ms(1000);
}
}
Full OLED_menu .c-file (relevant functions works without OLED.h definitions):
#include "OLED.h"
#include "OLED_menu.h"
void menu_init()
{
menu_page_address_offset = 0x1C01;
game_setting_address_offset = 0x1F01;
game_status = game_setting_address_offset;
game_setting_address_offset += 1;
uint8_t alternatives[6];
game_status->parameter = &game_parameters_array[RUN_STATUS];
game_status->alternatives[0] = OFF;
game_status->alternatives[1] = ON;
game_status->alternatives_number = 2;
start_game = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&start_game->title, "Start game");
start_game->submenu_pages[0] = NULL;
start_game->parent_menu_page = main_menu;
start_game->submenu_pages_number = 0;
start_game->setting = &game_status;
solenoid_param = game_setting_address_offset;
game_setting_address_offset += 1;
solenoid_param->parameter = &game_parameters_array[SOLENOID];
solenoid_param->alternatives[0] = X_POSITION;
solenoid_param->alternatives[1] = Y_POSITION;
solenoid_param->alternatives[2] = LEFT_SLIDER;
solenoid_param->alternatives[3] = RIGHT_SLIDER;
solenoid_param->alternatives_number = 4;
solenoid_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&solenoid_control->title,"Solenoid");
solenoid_control->submenu_pages[0] = NULL;
solenoid_control->parent_menu_page = NULL;
solenoid_control->submenu_pages_number = 0;
solenoid_control->setting = &solenoid_param;
servo_param = game_setting_address_offset;
game_setting_address_offset += 1;
servo_param->parameter = &game_parameters_array[SERVO];
servo_param->alternatives[0] = X_POSITION;
servo_param->alternatives[1] = Y_POSITION;
servo_param->alternatives[2] = LEFT_SLIDER;
servo_param->alternatives[3] = RIGHT_SLIDER;
servo_param->alternatives_number = 4;
servo_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&servo_control->title, "Servo");
servo_control->submenu_pages[0] = NULL;
servo_control->parent_menu_page = NULL;
servo_control->submenu_pages_number = 0;
servo_control->setting = &servo_param;
motor_param = game_setting_address_offset;
game_setting_address_offset += 1;
motor_param->parameter = &game_parameters_array[MOTOR];
motor_param->alternatives[0] = X_POSITION;
motor_param->alternatives[1] = Y_POSITION;
motor_param->alternatives[2] = LEFT_SLIDER;
motor_param->alternatives[3] = RIGHT_SLIDER;
motor_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&motor_control->title, "Motor");
motor_control->submenu_pages[0] = NULL;
motor_control->parent_menu_page = NULL;
motor_control->submenu_pages_number = 0;
motor_control->setting = &motor_param;
controller_layout = menu_page_address_offset;
//printf("Controller_layout addr: , %d\n", (int)menu_page_address_offset);
menu_page_address_offset += 1;
/*
strcpy(controller_layout->title, "Controller Layout");
controller_layout->submenu_pages[0] = motor_control;
printf("motor_control : %X\n", motor_control);
controller_layout->submenu_pages[1] = servo_control;
controller_layout->submenu_pages[2] = solenoid_control;
controller_layout->parent_menu_page = NULL;
controller_layout->submenu_pages_number = 3;
controller_layout->setting = NULL;
settings_advanced = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(settings_advanced->title, "Advanced Settings");
settings_advanced->submenu_pages[0] = NULL;
settings_advanced->parent_menu_page = NULL;
settings_advanced->submenu_pages_number = 0;
settings_advanced->setting = NULL;
difficulty_param->parameter = &game_parameters_array[DIFFICULTY];
difficulty_param->alternatives[0] = DIFFICULTY_EASY;
difficulty_param->alternatives[1] = DIFFICULTY_NORMAL;
difficulty_param->alternatives[2] = DIFFICULTY_HARD;
difficulty_param->alternatives_number = 3;
settings_difficulty = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(settings_difficulty->title, "Difficulty");
settings_difficulty->submenu_pages[0] = NULL;
settings_difficulty->parent_menu_page = NULL;
settings_difficulty->submenu_pages_number = 0;
settings_difficulty->setting = &difficulty_param;
menu_setting = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(menu_setting->title, "Settings");
menu_setting->submenu_pages[0] = controller_layout;
menu_setting->submenu_pages[1] = settings_difficulty;
menu_setting->submenu_pages[2] = settings_advanced;
//printf("Child 1 before: %d, %d",menu_setting->submenu_pages[0], controller_layout);
menu_setting->parent_menu_page = NULL;
menu_setting->submenu_pages_number = 3;
menu_setting->setting = NULL;
*/
menu_setting = menu_page_address_offset;
menu_page_address_offset += 1;
main_menu = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(main_menu->title, "Main Menu");
main_menu->submenu_pages[0] = start_game;
main_menu->submenu_pages[1] = menu_setting;
main_menu->parent_menu_page = NULL;
main_menu->submenu_pages_number = 2;
main_menu->setting = NULL;
menu_assign_parents(&main_menu);
}
void game_setting_init(game_setting* setting, uint8_t* parameter, uint8_t* alternatives, uint8_t elements)
{
setting->parameter = parameter;
for (int i; i < elements; i++)
{
setting->alternatives[i] = alternatives[i];
}
}
int menu_assign_parents(menu_page* parent)
{
if(parent->submenu_pages_number > 6)
{
return -1;
}
for (int i; i < parent->submenu_pages_number; i++)
{
parent->submenu_pages[i]->parent_menu_page = parent;
if(menu_assign_parents(parent->submenu_pages[i]) == -1)
{
return -1;
}
}
return 0;
}
int menu_page_print(menu_page* page)
{
OLED_SRAM_Position_reset();
OLED_TextBox_clear((boundary) {0,127,0,7});
OLED_Goto_position(0,40);
//printf("%d parent, ", page->submenu_pages_number);
OLED_String_print(page->title, FONT_LARGE);
for (int i = 0; i < page->submenu_pages_number; i++)
{
OLED_Goto_position(i+1,5);
OLED_String_print(page->submenu_pages[i]->title, FONT_NORMAL);
//printf("%s\n", page->submenu_pages[i].title);
}
return 0;
}
menu_page* menu_page_select(menu_page* page,controller* C)
{
menu_page_print(page);
if(page->submenu_pages_number <= 0)
{
return (menu_page*)-1;
}
int submenu_number = -1;
int submenu_result = -1;
controller_direction generalDirection_prev;
while(!C->rightButton)
{
updateController(C);
if(generalDirection_prev != C->J.generalDirection)
{
switch(C->J.generalDirection)
{
case (DOWN):
submenu_number = (submenu_number + 1)%page->submenu_pages_number;
break;
case (UP):
submenu_number--;
if(submenu_number < 0)
{
submenu_number = page->submenu_pages_number-1;
}
break;
}
menu_page_selection_mark(submenu_number+1, page);
generalDirection_prev = C->J.generalDirection;
}
}
return &(page->submenu_pages[submenu_number]);
}
int TextBox_init(OLED_TextBox** box, char* str, TextBox_pos position, uint8_t line)
{
uint8_t StringLength = strlen(str);
printf("%d\n\r", StringLength);
if (118 / StringLength >= FONT_LARGE)
{
(*box)->FontSize = FONT_LARGE;
}
else if (118 / StringLength >= FONT_NORMAL)
{
(*box)->FontSize = FONT_NORMAL;
}
else if (118 / StringLength >= FONT_SMALL)
{
(*box)->FontSize = FONT_SMALL;
}
printf("%d\n\r", (*box)->FontSize);
switch (position)
{
case TEXBOX_LEFT:
(*box)->Boundaries = (boundary){5,5+StringLength*(*box)->FontSize,line,line};
case TEXTBOX_CENTER:
printf("%d\n\r", (128-(*box)->FontSize*StringLength)/2);
(*box)->Boundaries = (boundary){(128-(*box)->FontSize*StringLength)/2, (128+StringLength*(*box)->FontSize+1)/2,line,line};
printf("%d, %d, %d, %d nr1\n\r", (*box)->Boundaries.Left, (*box)->Boundaries.Right, (*box)->Boundaries.Top, (*box)->Boundaries.Bottom);
//printf("%d\n\r", (*box)->FontSize);
case TEXTBOX_RIGHT:
(*box)->Boundaries =(boundary){128-5-StringLength*(*box)->FontSize, 128-5,line,line};
}
(*box)->string = str;
return 0;
}
int menu_page_selection_mark(uint8_t rowIndex, menu_page* menu)
{
if(rowIndex < 1)
{
return -1;
}
//printf("Current index: %s\n", menu->submenu_pages[rowIndex].title);
static int rowIndex_prev = -1;
if(rowIndex_prev > -1)
{
OLED_Clear_line(rowIndex_prev);
OLED_Goto_position(rowIndex_prev, 5);
printf("title: %s\n", menu->submenu_pages[rowIndex_prev-1]->title);
OLED_String_print(menu->submenu_pages[rowIndex_prev-1]->title, FONT_LARGE);
}
OLED_Clear_line(rowIndex);
OLED_Goto_position(rowIndex, 7);
OLED_String_print(menu->submenu_pages[rowIndex-1]->title, FONT_LARGE);
OLED_String_print(" <-", FONT_LARGE);
rowIndex_prev = rowIndex;
return rowIndex;
}
void menu_page_print_data()
{
menu_page* page = main_menu;
printf("Menu page %s: Children: ", page->title);
for (int i; i < page->submenu_pages_number; i++)
{
printf("%s ", page->submenu_pages[i]->title);
}
printf("Parent: %s", page->parent_menu_page->title);
}
int menu_print_parameters(game_setting* settings, controller* C)
{
static uint8_t current_position = 1;
controller_direction generalDirection_prev;
menu_print_parameter_line(settings, LEFT, current_position);
while(!C->leftButton)
{
if(C->J.generalDirection != generalDirection_prev)
{
if (C->J.generalDirection == LEFT)
{
current_position = menu_print_parameter_line(settings, LEFT, current_position);
}
else if(C->J.generalDirection == RIGHT)
{
current_position = menu_print_parameter_line(settings, RIGHT, current_position);
}
}
}
}
int menu_print_parameter_line(game_setting* setting, controller_direction direction, uint8_t position)
{
char* string;
uint8_t next_position;
if(setting->alternatives_number == 0)
{
return -1;
}
if(direction == LEFT)
{
next_position = position -1;
}
else if(direction == RIGHT)
{
next_position = position +1;
}
OLED_Clear_line(6);
OLED_Goto_position(6,127);
OLED_String_print("<-", FONT_LARGE);
sprintf(&string, setting->alternatives[next_position]);
OLED_String_print(string, FONT_LARGE);
OLED_String_print("->", FONT_LARGE);
return next_position;
}
int menu_assign_parameters(menu_page* page, controller* C)
{
}
int menu_run(menu_page* page, controller* C)
{
menu_page* next_submenu_page;
menu_page* current_page = page;
while(next_submenu_page != -1)
{
current_page = next_submenu_page;
next_submenu_page = menu_page_select(current_page, C);
}
}
OLED_menu.h-file:
#ifndef OLED_MENU_H
#define OLED_MENU_H
#include "symbols_enums.h"
#include "OLED.h"
#include "multiboard.h"
#include "CAN_message_IDs.h"
#include <assert.h>
#include <string.h>
#include <avr/delay.h>
typedef struct menu_page menu_page;
typedef struct game_setting game_setting;
struct game_setting
{
uint8_t* parameter;
uint8_t alternatives[6];
uint8_t alternatives_number;
};
struct menu_page
{
char title[12];
menu_page* submenu_pages[4];
menu_page* parent_menu_page;
uint8_t submenu_pages_number;
//Used to set values for settings:
game_setting* setting;
};
typedef enum {TEXBOX_LEFT, TEXTBOX_CENTER, TEXTBOX_RIGHT}TextBox_pos;
static volatile menu_page* menu_page_address_offset;
static volatile game_setting* game_setting_address_offset;
static uint8_t game_parameters_array[5];
//Indicates if the game should start/stop:
static volatile game_setting* game_status;
static volatile menu_page* start_game;
//***********************************
static volatile game_setting* solenoid_param;
static volatile menu_page* solenoid_control;
static volatile game_setting* servo_param;
static volatile menu_page* servo_control;
static volatile game_setting* motor_param;
static volatile menu_page* motor_control; //Controller layout
//***********************************
static volatile menu_page* controller_layout;
static volatile menu_page* settings_advanced;
static volatile game_setting* difficulty_param;
static volatile menu_page* settings_difficulty;
static volatile menu_page* menu_setting;
static volatile menu_page* main_menu;
int menu_page_init(char*, menu_page*, menu_page*);
int menu_page_print(menu_page* page);
menu_page* menu_page_select(menu_page* page,controller* C);
int menu_page_selection_mark(uint8_t, menu_page*);
void menu_page_print_data();
int menu_print_parameter_line(game_setting*, controller_direction , uint8_t);
//int TextBox_init(OLED_TextBox**, char*, TextBox_pos, uint8_t);
#endif // OLED_MENU_H
I changed it to manually initialize one struct member at a time, which seems to work. However, when executing the program crashes before the menu_init() finishes due to these initializations:
menu_setting->submenu_pages[0] = controller_layout;
menu_setting->submenu_pages[1] = settings_difficulty;
menu_setting->submenu_pages[2] = settings_advanced;
main_menu->submenu_pages[0] = start_game;
main_menu->submenu_pages[1] = menu_setting;
controller_layout->submenu_pages[1] = servo_control;
controller_layout->submenu_pages[2] = solenoid_control
The initialization is providing the address of a thing, not the thing itself.
struct game_setting {
uint8_t parameter; // this is a byte
...
};
then in main()
{
static uint8_t game_parameters_array[6];
static struct game_setting game_status = {
&game_parameters_array[RUN_STATUS], // this is an address, not a byte
...
}
Also, I didn't see the definition of RUN_STATUS - is there any chance it's not a constant value? If it's a macro for something that can change (like a status flag), then it's not something suitable for indexing at load time to initialize this.
Related
code:
```
#include "pch.h"
#include
extern "C"
{
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <libavcodec/avcodec.h>
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/avutil.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include <libavutil/rational.h>
//#include "libavutil/avassert.h"
//#include "libavutil/attributes.h"
//#include "libavutil/avassert.h"
//#include "libavutil/frame.h"
//#include "libavutil/imgutils.h"
//#include "internal1.h"
//#include "libavutil/samplefmt.h"
}
#include <vld.h>
//#include "avcodec.h"
//#include "frame_thread_encoder.h"
//#include "internal.h"
// Globals
AVCodec* m_pCodec = NULL;
AVStream *m_pStream = NULL;
AVOutputFormat* m_pFormat = NULL;
AVFormatContext* m_pFormatContext = NULL;
AVCodecContext* m_pCodecContext = NULL;
AVFrame* m_pFrame = NULL;
int m_frameIndex;
// Output format
AVPixelFormat m_pixType = AV_PIX_FMT_NV12;
// Use for mpeg4
//AVPixelFormat m_pixType = AV_PIX_FMT_YUV420P;
// Output frame rate
int m_frameRate = 30;
// Output image dimensions
int m_imageWidth = 256;
int m_imageHeight = 1537;
// Number of frames to export
int m_frameCount = 20000;
// Output file name
const char* m_fileName = "test.h264";
// Output file type
const char* m_fileType = "H264";
// Codec name used to encode
const char* m_encoderName = "h264_qsv";
// use for mpeg4
//const char* m_encoderName = "mpeg4";
// Target bit rate
int m_targetBitRate = 400000;
void addVideoStream()
{
m_pStream = avformat_new_stream(m_pFormatContext, m_pCodec);
m_pStream->id = m_pFormatContext->nb_streams - 1;
m_pStream->time_base = m_pCodecContext->time_base;
m_pStream->codec->pix_fmt = m_pixType;
m_pStream->codec->flags = m_pCodecContext->flags;
m_pStream->codec->width = m_pCodecContext->width;
m_pStream->codec->height = m_pCodecContext->height;
m_pStream->codec->time_base = m_pCodecContext->time_base;
m_pStream->codec->bit_rate = m_pCodecContext->bit_rate;
}
AVFrame* allocatePicture(enum AVPixelFormat pix_fmt, int width, int height)
{
AVFrame *frame;
frame = av_frame_alloc();
if (!frame)
{
return NULL;
}
frame->format = pix_fmt;
frame->width = width;
frame->height = height;
int checkImage = av_image_alloc(frame->data, frame->linesize, width, height, pix_fmt, 32);
if (checkImage < 0)
{
return NULL;
}
return frame;
}
bool initialize()
{
AVRational frameRate;
frameRate.den = m_frameRate;
frameRate.num = 1;
av_register_all();
m_pCodec = avcodec_find_encoder_by_name(m_encoderName);
if (!m_pCodec)
{
return false;
}
m_pCodecContext = avcodec_alloc_context3(m_pCodec);
m_pCodecContext->width = m_imageWidth;
m_pCodecContext->height = m_imageHeight;
m_pCodecContext->time_base = frameRate;
m_pCodecContext->gop_size = 0;
m_pCodecContext->pix_fmt = m_pixType;
m_pCodecContext->codec_id = m_pCodec->id;
m_pCodecContext->bit_rate = m_targetBitRate;
av_opt_set(m_pCodecContext->priv_data, "+CBR", "", 0);
return true;
}
bool startExport()
{
m_frameIndex = 0;
char fakeFileName[512];
int checkAllocContext = avformat_alloc_output_context2(&m_pFormatContext, NULL, m_fileType, fakeFileName);
if (checkAllocContext < 0)
{
return false;
}
if (!m_pFormatContext)
{
return false;
}
m_pFormat = m_pFormatContext->oformat;
if (m_pFormat->video_codec != AV_CODEC_ID_NONE)
{
addVideoStream();
int checkOpen = avcodec_open2(m_pCodecContext, m_pCodec, NULL);
if (checkOpen < 0)
{
return false;
}
m_pFrame = allocatePicture(m_pCodecContext->pix_fmt, m_pCodecContext->width, m_pCodecContext->height);
if (!m_pFrame)
{
return false;
}
m_pFrame->pts = 0;
}
int checkOpen = avio_open(&m_pFormatContext->pb, m_fileName, AVIO_FLAG_WRITE);
if (checkOpen < 0)
{
return false;
}
av_dict_set(&(m_pFormatContext->metadata), "title", "QS Test", 0);
int checkHeader = avformat_write_header(m_pFormatContext, NULL);
if (checkHeader < 0)
{
return false;
}
return true;
}
int processFrame(AVPacket& avPacket)
{
avPacket.stream_index = 0;
avPacket.pts = av_rescale_q(m_pFrame->pts, m_pStream->codec->time_base, m_pStream->time_base);
avPacket.dts = av_rescale_q(m_pFrame->pts, m_pStream->codec->time_base, m_pStream->time_base);
m_pFrame->pts++;
int retVal = av_interleaved_write_frame(m_pFormatContext, &avPacket);
return retVal;
}
bool exportFrame()
{
int success = 1;
int result = 0;
AVPacket avPacket;
av_init_packet(&avPacket);
avPacket.data = NULL;
avPacket.size = 0;
AVPacket* avPacket1 = new AVPacket();
av_init_packet(avPacket1);
avPacket1->data = NULL;
avPacket1->size = 0;
fflush(stdout);
std::cout << "Before avcodec_encode_video2 for frame: " << m_frameIndex << std::endl;
success = avcodec_encode_video2(m_pCodecContext, &avPacket, m_pFrame, &result);
std::cout << "After avcodec_encode_video2 for frame: " << m_frameIndex << std::endl;
if (result)
{
success = processFrame(avPacket);
}
av_packet_unref(&avPacket);
av_free_packet(&avPacket);
//av_frame_free(&m_pFrame);
m_frameIndex++;
return (success == 0);
}
void endExport()
{
int result = 0;
int success = 0;
if (m_pFrame)
{
while (success == 0)
{
AVPacket avPacket;
av_init_packet(&avPacket);
avPacket.data = NULL;
avPacket.size = 0;
fflush(stdout);
success = avcodec_encode_video2(m_pCodecContext, &avPacket, NULL, &result);
if (result)
{
success = processFrame(avPacket);
}
av_packet_unref(&avPacket);
if (!result)
{
break;
}
}
}
if (m_pFormatContext)
{
av_write_trailer(m_pFormatContext);
if (m_pFrame)
{
av_frame_free(&m_pFrame);
}
avio_closep(&m_pFormatContext->pb);
avformat_free_context(m_pFormatContext);
m_pFormatContext = NULL;
}
}
void cleanup()
{
if (m_pFrame || m_pCodecContext)
{
if (m_pFrame)
{
av_frame_free(&m_pFrame);
}
if (m_pCodecContext)
{
avcodec_close(m_pCodecContext);
av_free(m_pCodecContext);
}
}
}
int main()
{
bool success = true;
if (initialize())
{
if (startExport())
{
for (int loop = 0; loop < m_frameCount; loop++)
{
if (!exportFrame())
{
std::cout << "Failed to export frame\n";
success = false;
break;
}
}
endExport();
}
else
{
std::cout << "Failed to start export\n";
success = false;
}
cleanup();
}
else
{
std::cout << "Failed to initialize export\n";
success = false;
}
if (success)
{
std::cout << "Successfully exported file\n";
}
return 1;
}
```
When I set the m_imageHeight to 1536, the memory usage is very high. But when set to 1535 or 1537 or other values, the memory usage is normal, can you tell me why?
I have navigated to avcodec_encode_video2
enter link description here
I am using the code from the link
I have updated to the latest Intel® Graphics Driver
I'm getting a segmentation fault error somewhere in my insert function. It says that its due to one of the 'strcmp' comparisons but i cant find the issue after looking at all of them.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define INITIAL_CAPACITY 8
typedef struct node
{
unsigned int val;
char *key;
bool del;
} Node;
typedef Node * NodePtr;
typedef struct hashMap
{
NodePtr array;
size_t capacity;
size_t size;
} HashMap;
typedef HashMap * HMPtr;
//|-------------------------
HMPtr create();
void insert(HMPtr map, char *str);
//y
void resize_insert(HMPtr map, char *str);
//y
void print(HMPtr map);
void destroy(HMPtr *mapPtr);
void resize(HMPtr map);
//y
unsigned int hash(char *str);
//y
unsigned int pop(HMPtr map, char *key);
//y
//|-------------------------
int main(void)
{
HMPtr map = create();
insert(map, "Keathan");
insert(map, "Trey");
insert(map, "Noah");
insert(map, "Kleiner");
insert(map, "data");
insert(map, "Matthew");
print(map);
destroy(&map);
return 0;
}
unsigned int pop(HMPtr map, char *str)
{
unsigned int val = hash(str);
size_t h = (size_t)val;
size_t index = h % map->capacity;
for(size_t i = 0; map->array[index].key && strcmp(str, map->array[index].key);index = (h + ((++i) + i*i)/2)%map->capacity);
if (map->array[index].key)
{
map->array[index].del = true;
return map->array[index].val;
}
return 0;
}
unsigned int hash(char *str)
{
unsigned int out = 0;
unsigned int base = 31;
unsigned int factor = 1;
for (size_t i = 0; str[i] != 0; ++i)
{
out += (unsigned int)str[i] * factor;
factor *= base;
}
return out;
}
void resize(HMPtr map)
{
NodePtr old = map->array;
size_t old_capacity = map->capacity;
map->capacity = old_capacity * 2;
map->array = calloc(map->capacity, sizeof(Node));
for(size_t i = 0; i < old_capacity; ++i)
{
if(old[i].key)
{
if(old[i].del)
free(old[i].key);
else
resize_insert(map, old[i].key);
}
}
free(old);
}
void resize_insert(HMPtr map, char *str)
{
unsigned int val = hash(str);
size_t h = (size_t)val;
size_t index = h % map->capacity;
for (size_t i = 0; map->array[index].key; index = (h + ((++i) + i*i)/2)%map->capacity);
map->array[index].key = str;
map->array[index].val = val;
++(map->size);
}
void insert(HMPtr map, char *str)
{
unsigned int val = hash(str);
size_t h = (size_t)val;
size_t index = h % map->capacity;
size_t i;
NodePtr deleted = NULL;
for(i = 0; map->array[index].key && strcmp(str, map->array[index].key);index = (h + ((++i) + i*i)/2)%map->capacity)
if(!deleted && map->array[index].del)
{
deleted = map->array + index;
for(index = (h + ((++i) + i*i)/2)%map->capacity; map->array[index].key && strcmp(str, map->array[index].key); index = (h + ((++i) + i*i)/2)%map->capacity);
break;
}
if (map->array[index].key == NULL)
{
if(deleted)
{
free(deleted->key);
deleted->del = false;
index = deleted - map->array;
}
else if (++(map->size) >= 0.7*map->capacity)
{
resize(map);
index = h % map->capacity;
for (i = 0; map->array[index].key; index = (h + ((++i) + i*i)/2)%map->capacity);
}
map->array[index].key = calloc(strlen(str)+1, sizeof(char));
strcpy(map->array[index].key, str);
}
else
map->array[index].val = val;
}
HMPtr create()
{
HMPtr newList = malloc(sizeof(HashMap));
newList->size = 0;
newList->capacity = INITIAL_CAPACITY;
newList->array = calloc(newList->capacity, sizeof(NodePtr));
return newList;
}
void destroy(HMPtr *mapPtr)
{
free((*mapPtr)->array);
free(*mapPtr);
*mapPtr = NULL;
}
void print(HMPtr map)
{
for (size_t i = 0; i < map->capacity; ++i)
printf("%s;%u\n", map->array[i].key, map->array[i].val);
}
This is the Error i recieved after running on gdb
'''
Program received signal SIGSEGV, Segmentation fault.
__strcmp_sse2_unaligned ()
at ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S:30
30 ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S: No such file or
directory.
'''
If anyone could spot the issue then that would help a lot. Thanks!
sizeof(nodePtr) is size of pointer you need sizeof(struct Node)
HMPtr create()
{
HMPtr newList = malloc(sizeof(HashMap));
newList->size = 0;
newList->capacity = INITIAL_CAPACITY;
newList->array = calloc(newList->capacity, sizeof(*newList->array));
return newList;
}
I am trying to build an efficient concurrent hash map using pthreads, C.
Following is my implementation
#include <stdlib.h>
#include <stddef.h>
#include <pthread.h>
#include <stdint.h>
#include <limits.h>
#include <stdio.h>
#include <linux/limits.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#define ENTRIES_PER_BUCKET 3
struct Bucket
{
pthread_mutex_t mutex;
void **keys;
int *vals;
struct Bucket *next;
};
struct Concurrent_Map
{
struct Bucket *buckets;
map_keys_equality *keys_eq;
map_key_hash *khash;
int capacity;
};
int concurrent_map_allocate /*# <t> #*/ (map_keys_equality *keq, map_key_hash *khash,
unsigned capacity,
struct Concurrent_Map **map_out)
{
struct Concurrent_Map *old_map_val = *map_out;
struct Concurrent_Map *map_alloc = malloc(sizeof(struct Concurrent_Map));
if (map_alloc == NULL)
{
return 0;
}
*map_out = (struct Concurrent_Map *)map_alloc;
struct Bucket *buckets_alloc = (struct Bucket *)malloc(sizeof(struct Bucket) * (int)capacity);
if (buckets_alloc == NULL)
{
free(map_alloc);
*map_out = old_map_val;
return 0;
}
(*map_out)->buckets = buckets_alloc;
(*map_out)->capacity = capacity;
(*map_out)->keys_eq = keq;
(*map_out)->khash = khash;
unsigned i;
for (i = 0; i < capacity; i++)
{
if (pthread_mutex_init(&((*map_out)->buckets[i].mutex), NULL) == 0)
{
void **key_alloc = malloc(sizeof(void *) * (ENTRIES_PER_BUCKET));
if (key_alloc != NULL)
{
(*map_out)->buckets[i].keys = key_alloc;
int k;
for (k = 0; k < ENTRIES_PER_BUCKET; k++)
{
(*map_out)->buckets[i].keys[k] = NULL;
}
}
int *vals_alloc = malloc(sizeof(int) * (ENTRIES_PER_BUCKET));
if (vals_alloc != NULL)
{
(*map_out)->buckets[i].vals = vals_alloc;
int k;
for (k = 0; k < ENTRIES_PER_BUCKET; k++)
{
(*map_out)->buckets[i].vals[k] = -1;
}
}
(*map_out)->buckets[i].next = NULL;
}
}
// todo exceptions in allocation
return 1;
}
static unsigned loop(unsigned k, unsigned capacity)
{
unsigned g = k % capacity;
unsigned res = (g + capacity) % capacity;
return res;
}
int concurrent_map_get(struct Concurrent_Map *map, void *key, int *value_out)
{
map_key_hash *khash = map->khash;
unsigned hash = khash(key);
unsigned start = loop(hash, map->capacity);
unsigned bucket_index = loop(start + 0, map->capacity);
if (bucket_index < map->capacity)
{
struct Bucket *bucket = &(map->buckets[bucket_index]);
pthread_mutex_t mutex = bucket->mutex;
pthread_mutex_lock(&mutex);
int j;
do
{
for (j = 0; j < ENTRIES_PER_BUCKET; j++)
{
int val = bucket->vals[j];
if (map->keys_eq(bucket->keys[j], key))
{
if (bucket->vals[j] == val)
{
*value_out = val;
return 1;
}
else
{
*value_out = -1;
return 0;
}
}
}
if (bucket->next != NULL)
{
bucket = (bucket->next);
}
else
{
break;
pthread_mutex_unlock(&mutex);
}
pthread_mutex_unlock(&mutex);
} while (1);
}
*value_out = -1;
return 0;
}
int concurrent_map_put(struct Concurrent_Map *map, void *key, int value)
{
map_key_hash *khash = map->khash;
unsigned hash = khash(key);
unsigned start = loop(hash, map->capacity);
unsigned bucket_index = loop(start + 0, map->capacity);
struct Bucket *bucket = &(map->buckets[bucket_index]);
int j;
do
{
pthread_mutex_t mutex = bucket->mutex;
int j;
pthread_mutex_lock(&mutex);
for (j = 0; j < ENTRIES_PER_BUCKET; j++)
{
if (map->keys_eq(bucket->keys[j], key))
{
pthread_mutex_unlock(&mutex);
return 0;
}
else if (bucket->keys[j] == NULL)
{
bucket->vals[j] = value;
bucket->keys[j] = key;
pthread_mutex_unlock(&mutex);
return 1;
}
}
if (bucket->next == NULL)
{
// allocate a new bucket
struct Bucket *new_bucket = malloc(sizeof(struct Bucket));
if (pthread_mutex_init(&(new_bucket->mutex), NULL) == 0)
{
void **key_alloc = malloc(sizeof(void *) * (ENTRIES_PER_BUCKET));
if (key_alloc != NULL)
{
new_bucket->keys = key_alloc;
int k;
for (k = 0; k < ENTRIES_PER_BUCKET; k++)
{
new_bucket->keys[k] = NULL;
}
}
int *vals_alloc = malloc(sizeof(int) * (ENTRIES_PER_BUCKET));
if (vals_alloc != NULL)
{
new_bucket->vals = vals_alloc;
int k;
for (k = 0; k < ENTRIES_PER_BUCKET; k++)
{
new_bucket->vals[k] = -1;
}
}
bucket->next = new_bucket;
}
}
pthread_mutex_unlock(&mutex);
bucket = bucket->next;
} while (1);
return 0;
}
int concurrent_map_erase(struct Concurrent_Map *map, void *key, void **trash)
{
map_key_hash *khash = map->khash;
unsigned hash = khash(key);
unsigned start = loop(hash, map->capacity);
unsigned bucket_index = loop(start + 0, map->capacity);
struct Bucket *bucket = &(map->buckets[bucket_index]);
int j;
do
{
pthread_mutex_t mutex = bucket->mutex;
int j;
pthread_mutex_lock(&mutex);
for (j = 0; j < ENTRIES_PER_BUCKET; j++)
{
if (map->keys_eq(bucket->keys[j], key))
{
bucket->vals[j] = -1;
bucket->keys[j] = NULL;
pthread_mutex_unlock(&mutex);
return 1;
}
}
pthread_mutex_unlock(&mutex);
if (bucket->next != NULL)
{
bucket = (bucket->next);
}
else
{
break;
}
} while (1);
return 0;
}
int concurrent_map_size(struct Concurrent_Map *map)
{
int num_buckets = 0;
struct Bucket *buckets = map->buckets;
unsigned i;
for (i = 0; i < map->capacity; i++)
{
struct Bucket bucket = buckets[i];
do
{
num_buckets++;
if (bucket.next != NULL)
{
bucket = *(bucket.next);
}
else
{
break;
}
} while (1);
}
return num_buckets * ENTRIES_PER_BUCKET;
}
struct FlowId
{
int src_port;
int dst_port;
int src_ip;
int dst_ip;
int internal_device;
int protocol;
};
bool FlowId_eq(void *a, void *b)
{
if (a == NULL || b == NULL)
{
return false;
}
struct FlowId *id1 = a;
struct FlowId *id2 = b;
return (id1->src_port == id2->src_port) && (id1->dst_port == id2->dst_port) && (id1->src_ip == id2->src_ip) && (id1->dst_ip == id2->dst_ip) && (id1->internal_device == id2->internal_device) && (id1->protocol == id2->protocol);
}
unsigned FlowId_hash(void *obj)
{
struct FlowId *id = obj;
unsigned hash = 0;
hash = __builtin_ia32_crc32si(hash, id->src_port);
hash = __builtin_ia32_crc32si(hash, id->dst_port);
hash = __builtin_ia32_crc32si(hash, id->src_ip);
hash = __builtin_ia32_crc32si(hash, id->dst_ip);
hash = __builtin_ia32_crc32si(hash, id->internal_device);
hash = __builtin_ia32_crc32si(hash, id->protocol);
return hash;
}
struct Concurrent_Map *concurrent_map;
#define NUM_THREADS 2
#define NUM_PACKETS 10000000
void *expirator(void *arg)
{
// printf("Thread started executing\n");
unsigned i = 0;
int error = 0;
unsigned packet_count = NUM_PACKETS / NUM_THREADS;
while (i < packet_count)
{
i++;
struct FlowId *id = malloc(sizeof(struct FlowId));
struct FlowId *id1 = malloc(sizeof(struct FlowId));
id->dst_ip = 1;
id->src_ip = 1;
id->internal_device = 1;
id->protocol = 1;
id->src_port = 1;
id->dst_port = rand() % 65536;
id1->dst_ip = 1;
id1->src_ip = 1;
id1->internal_device = 1;
id1->protocol = 1;
id1->src_port = 1;
id1->dst_port = rand() % 65536;
int external_port = rand() % 65536;
int external;
concurrent_map_erase(concurrent_map, id, NULL);
concurrent_map_put(concurrent_map, id, external_port);
concurrent_map_get(concurrent_map, id, &external);
if (external_port != external)
{
error++;
}
else
{
}
}
return NULL;
}
int main()
{
clock_t begin = clock();
concurrent_map_allocate(FlowId_eq, FlowId_hash, 65536, &(concurrent_map));
pthread_t *threads = malloc(sizeof(pthread_t) * NUM_THREADS);
int i;
for (i = 0; i < NUM_THREADS; i++)
{
if (pthread_create(&threads[i], NULL, expirator, NULL) != 0)
{
printf("Error creating threads");
exit(0);
}
}
for (i = 0; i < NUM_THREADS; i++)
{
if (pthread_join(threads[i], NULL) != 0)
{
printf("Error joining threads");
exit(0);
}
}
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("%lf\n", time_spent);
return 0;
}
Here is how to run this program.
gcc concurrent_map.c -o test-concurrent-new -lpthread -msse4.2 -O3
Then I measure the execution time for a fixed workload and following are the time values I observed.
1: 3.29
2: 6.687811
3: 5.88
4: 6.23
5: 6.38
6: 6.52
7: 6.74
8: 6.82
It seems that when the number of threads is increased the execution time increases and remains almost same.
I profiled this code using Mutrace, which looks for mutex contention. It turns out that
No mutex contended according to filtering parameters.
I checked the number of cache misses, and it turned out that number of cache misses are roughly equal when the number of threads is modified.
Why does not the execution time decrease when the number of threads increase?
I am running this on a 32 core machine
rand() is usually not suited for multi threaded execution. Instead use rand_r().
Also use linux time tool for timing the application.
Your workload generation imposes a huge overhead, and I assume it is the bottleneck here, not the concurrent hash map
I am on stm32f103c8t6 with STDP-Lib, using stm32's usb library for virtual com port and wanna to talk with the µC via termios-Pc-program. The termios program can read the data the chip is sending via USB, but when I wanna answer, the chip is not reacting on the data I send. What am I doing wrong when sending?
The termios-program:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
typedef union {
int num;
char part[2];
} _16to8;
static void sendData(int tty, unsigned char c) {
write(tty, &c, 1);
}
static unsigned char readData(int tty) {
unsigned char c;
while(read(tty, &c, 1) <= 0);
return c;
}
static unsigned char* readALotOfData(int tty, int len) {
unsigned char* c = NULL;
c = calloc(len, sizeof(unsigned char));
for(int i = 0; i < len; i++) {
c[i] = readData(tty);
}
return c;
}
static void sendCmd(int tty, char* c, size_t len) {
unsigned char* a = NULL;
int i = 0;
a = calloc(len, sizeof(unsigned char));
memcpy(a, c, len);
for(; i < len; i++) {
sendData(tty, a[i]);
}
free(a);
a = NULL;
}
int main(int argc, char** argv) {
struct termios tio;
int tty_fd;
FILE* fd;
struct stat st;
unsigned char c;
unsigned char* buf = NULL;
buf = calloc(4096, sizeof(unsigned char));
memset(&tio, 0, sizeof(tio));
tio.c_cflag = CS8;
tty_fd = open(argv[1], O_RDWR | O_NONBLOCK);
if(tty_fd == -1) {
printf("failed to open port\n");
return 1;
}
char mode;
if(!strcmp(argv[2], "flash")) {
mode = 1;
fd = fopen(argv[3], "r");
if(fd == NULL) {
printf("failed to open file\n");
return 1;
}
} else if(!strcmp(argv[2], "erase")) {
mode = 0;
} else {
printf("unknown operation mode\n");
return 1;
}
cfsetospeed(&tio, B115200);
cfsetispeed(&tio, B115200);
tcsetattr(tty_fd, TCSANOW, &tio);
unsigned char* id = readALotOfData(tty_fd, 20);
printf("%s\n", id);
if(strstr((const char*)id, "1234AABBCC1234")) {
sendCmd(tty_fd, "4321CCBBAA4321", 14);
printf("id verified\n");
} else {
printf("Could not identify device\n");
return 1;
}
if(mode) {
printf("going to flash the device\n");
sendCmd(tty_fd, "\xF1\xA5", 2);
stat(argv[3], &st);
int siz = st.st_size;
char sizR[2] = "\0";
sizR[1] = (unsigned char)(siz & 0xFF);
sizR[0] = (unsigned char)(siz >> 8);
_16to8 num = {0};
num.part[0] = sizR[0];
num.part[1] = sizR[1];
sendCmd(tty_fd, (char*)&num.num, 2);
char buffer[2] = {0};
int i = 0;
while(fread(&buffer, 1, 4, fd)) {
// sendCmd(tty_fd, buffer, 4);
// printf("%s\n", readALotOfData(tty_fd, 5));
}
} else {
printf("going to erase the device's memory\n");
sendCmd(tty_fd, (char*)0xE2A5, 2);
}
close(tty_fd);
return 0;
}
µCProgram:
#include "stm32f10x_conf.h"
#include "main.h"
void eraseFlashPage(uint8_t page) {
uint32_t addr = FLASH_ADDR + 0x400 * page;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR | FLASH_FLAG_EOP);
FLASH_ErasePage(addr);
FLASH_Lock();
}
void writeFlashAddr(uint8_t page, uint16_t offset, uint32_t data) {
uint32_t addr = FLASH_ADDR + 0x400 * page + offset;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR | FLASH_FLAG_EOP);
FLASH_ProgramWord(addr, (uint32_t)data);
FLASH_Lock();
}
uint32_t readFlashAddr(uint8_t page) {
uint32_t addr = FLASH_ADDR + 0x400 * page;
return *(uint32_t*)addr;
}
void TIM2_IRQHandler() {
static int count = 0;
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
if(mode) {
if(count == 2) {
count = 0;
GPIO_ToggleBits(GPIOA, GPIO_Pin_15);
}
count++;
} else {
GPIO_ToggleBits(GPIOA, GPIO_Pin_15);
}
}
}
int main() {
Set_System();
Set_USBClock();
USB_Interrupts_Config();
USB_Init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitTypeDef gpioStruct;
gpioStruct.GPIO_Pin = GPIO_Pin_15;
gpioStruct.GPIO_Mode = GPIO_Mode_Out_PP;
gpioStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpioStruct);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 200Hz -> 8Hz
TIM_TimeBaseInitTypeDef timStruct;
timStruct.TIM_Prescaler = 60000;
timStruct.TIM_CounterMode = TIM_CounterMode_Up;
timStruct.TIM_Period = 50; // ISR at 0.125s
timStruct.TIM_ClockDivision = TIM_CKD_DIV4;
timStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &timStruct);
TIM_Cmd(TIM2, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_InitTypeDef nvicStruct;
nvicStruct.NVIC_IRQChannel = TIM2_IRQn;
nvicStruct.NVIC_IRQChannelPreemptionPriority = 0;
nvicStruct.NVIC_IRQChannelSubPriority = 1;
nvicStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicStruct);
_delay_ms(500);
while(1) {
mode = 0;
Receive_length = 0;
char bootID[64];
for(volatile uint32_t cnt = 0; cnt < 4800 * 5000 / 4 / 25; cnt++) {
_printf("1234AABBCC1234");
CDC_Receive_DATA();
if(Receive_length >= 14) {
_gets((char*)&bootID, 14);
if(!memcmp(bootID, "4321CCBBAA4321", 14)) {
mode = 1;
break;
}
Receive_length = 0;
}
}
if(mode) {
uint32_t opt = 0;
_printf("operating mode?\n"); //debug
_gets((char*)&opt, 2);
if(opt == 0xF1A5) {
uint32_t len = 0;
uint32_t data = 0;
uint16_t i = 0;
_gets((char*)&len, 2);
_printf("writing %d/%d bytes starting at 0x%x\n", len, (117 - START_PAGE) * 1024, FLASH_ADDR); // debug
if(len < (117 - START_PAGE) * 1024) { // 117 or 64?
_printf("start writing to flash\n"); //debug
for(i = 0; i <= len / 1024; i++) {
eraseFlashPage(i);
_printf("erasing page %d\n", i); //debug
}
for(i = 0; i < len; i += 4) {
uint8_t page = i / 1024;
_printf("i:%d page:%d offset:%d\n", i, page, i - page * 1024); // debug
_gets((char*)&data, 4);
writeFlashAddr(page, i - page * 1024, data);
_printf("Page %d and 0x%x\n", page, FLASH_ADDR + 0x400 * page + i - page * 1024); // debug
}
_printf("done\n"); //debug
uint32_t sp = *(uint32_t*) FLASH_ADDR;
if((sp & 0x2FFF0000) == 0x20000000) {
TIM_Cmd(TIM2, DISABLE);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
NVIC->ICER[0] = 0xFFFFFFFF;
NVIC->ICER[1] = 0xFFFFFFFF;
NVIC->ICPR[0] = 0xFFFFFFFF;
NVIC->ICPR[1] = 0xFFFFFFFF;
PowerOff();
pFunction jmpUser;
uint32_t jmpAddr = *(__IO uint32_t*)(FLASH_ADDR + 4);
jmpUser = (pFunction)jmpAddr;
__set_MSP(*(__IO uint32_t*)FLASH_ADDR);
jmpUser();
}
} else {
_printf("not enought flash space available\n"); //debug
}
} else if(opt == 0xE2A5) {
for(int i = 0; i < (117 - START_PAGE); i++) {
eraseFlashPage(i);
_printf("erasing page %d\n", i); //debug
}
}
} else {
uint32_t sp = *(uint32_t*) FLASH_ADDR;
if((sp & 0x2FFF0000) == 0x20000000) {
TIM_Cmd(TIM2, DISABLE);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
NVIC->ICER[0] = 0xFFFFFFFF;
NVIC->ICER[1] = 0xFFFFFFFF;
NVIC->ICPR[0] = 0xFFFFFFFF;
NVIC->ICPR[1] = 0xFFFFFFFF;
PowerOff();
pFunction jmpUser;
uint32_t jmpAddr = *(__IO uint32_t*)(FLASH_ADDR + 4);
jmpUser = (pFunction)jmpAddr;
__set_MSP(*(__IO uint32_t*)FLASH_ADDR);
jmpUser();
}
}
}
}
I want to send the identification string and then enter the operations.... A friend of me got a working program with serialport-lib usage, but I wanna use termios...
Anyone an idea why the controller is not reacting on the sent data?
When compiling my code, I get the Data Memory overflow-error, even though all extra variables added since last successful compile, are declared with pointers to external SRAM-memory.
I found examples of specifying the external memory with linker flags, these did however not help. (Example for my SRAM memory range: 0x1000 ->0x1FFF):
-Wl,--section-start,.data=0x801000,--defsym=__heap_end=0x801FFF
Checking the box for 'External ram check for memory overflow' in AVR/GNU Common / General-settings did not solve the issue.
Code for the external declarations which are causing the overflow:
Header-file:
typedef struct menu_page menu_page;
typedef struct game_setting game_setting;
struct game_setting
{
uint8_t* parameter;
uint8_t alternatives[6];
uint8_t alternatives_number;
};
struct menu_page
{
char title[20];
menu_page* submenu_pages[4];
menu_page* parent_menu_page;
uint8_t submenu_pages_number;
//Used to set values for settings:
game_setting* setting;
};
typedef enum {TEXBOX_LEFT, TEXTBOX_CENTER, TEXTBOX_RIGHT}TextBox_pos;
static volatile menu_page* menu_page_address_offset;
static volatile game_setting* game_setting_address_offset;
static uint8_t game_parameters_array[5];
//Indicates if the game should start/stop:
static volatile game_setting* game_status;
static volatile menu_page* start_game;
//***********************************
static volatile game_setting* solenoid_param;
static volatile menu_page* solenoid_control;
static volatile game_setting* servo_param;
static volatile menu_page* servo_control;
static volatile game_setting* motor_param;
static volatile menu_page* motor_control; //Controller layout
//***********************************
static volatile menu_page* controller_layout;
static volatile menu_page* settings_advanced;
static volatile game_setting* difficulty_param;
static volatile menu_page* settings_difficulty;
static volatile menu_page* menu_setting;
static volatile menu_page* main_menu;
init-function in source file:
void menu_init()
{
menu_page_address_offset = 0x1C01;
game_setting_address_offset = 0x1F01;
game_status = game_setting_address_offset;
game_setting_address_offset += 1;
uint8_t alternatives[6];
game_status->parameter = &game_parameters_array[RUN_STATUS];
game_status->alternatives[0] = OFF;
game_status->alternatives[1] = ON;
game_status->alternatives_number = 2;
start_game = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&start_game->title, "Start game");
start_game->submenu_pages[0] = NULL;
start_game->parent_menu_page = main_menu;
start_game->submenu_pages_number = 0;
start_game->setting = &game_status;
solenoid_param = game_setting_address_offset;
game_setting_address_offset += 1;
solenoid_param->parameter = &game_parameters_array[SOLENOID];
solenoid_param->alternatives[0] = X_POSITION;
solenoid_param->alternatives[1] = Y_POSITION;
solenoid_param->alternatives[2] = LEFT_SLIDER;
solenoid_param->alternatives[3] = RIGHT_SLIDER;
solenoid_param->alternatives_number = 4;
solenoid_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&solenoid_control->title,"Solenoid");
solenoid_control->submenu_pages[0] = NULL;
solenoid_control->parent_menu_page = NULL;
solenoid_control->submenu_pages_number = 0;
solenoid_control->setting = &solenoid_param;
servo_param = game_setting_address_offset;
game_setting_address_offset += 1;
servo_param->parameter = &game_parameters_array[SERVO];
servo_param->alternatives[0] = X_POSITION;
servo_param->alternatives[1] = Y_POSITION;
servo_param->alternatives[2] = LEFT_SLIDER;
servo_param->alternatives[3] = RIGHT_SLIDER;
servo_param->alternatives_number = 4;
servo_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&servo_control->title, "Servo");
servo_control->submenu_pages[0] = NULL;
servo_control->parent_menu_page = NULL;
servo_control->submenu_pages_number = 0;
servo_control->setting = &servo_param;
motor_param = game_setting_address_offset;
game_setting_address_offset += 1;
motor_param->parameter = &game_parameters_array[MOTOR];
motor_param->alternatives[0] = X_POSITION;
motor_param->alternatives[1] = Y_POSITION;
motor_param->alternatives[2] = LEFT_SLIDER;
motor_param->alternatives[3] = RIGHT_SLIDER;
motor_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&motor_control->title, "Motor");
motor_control->submenu_pages[0] = NULL;
motor_control->parent_menu_page = NULL;
motor_control->submenu_pages_number = 0;
motor_control->setting = &motor_param;
#ifdef OLED_MENU_INIT_DEBUG
printf("Menu Title: %s\n", motor_control->title);
#endif
controller_layout = menu_page_address_offset;
//printf("Controller_layout addr: , %d\n", (int)menu_page_address_offset);
menu_page_address_offset += 1;
strcpy(controller_layout->title, "Controller Layout");
controller_layout->submenu_pages[0] = motor_control;
printf("motor_control : %X\n", motor_control);
controller_layout->submenu_pages[1] = servo_control;
controller_layout->submenu_pages[2] = solenoid_control;
controller_layout->parent_menu_page = NULL;
controller_layout->submenu_pages_number = 3;
controller_layout->setting = NULL;
settings_advanced = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(settings_advanced->title, "Advanced Settings");
settings_advanced->submenu_pages[0] = NULL;
settings_advanced->parent_menu_page = NULL;
settings_advanced->submenu_pages_number = 0;
settings_advanced->setting = NULL;
difficulty_param->parameter = &game_parameters_array[DIFFICULTY];
difficulty_param->alternatives[0] = DIFFICULTY_EASY;
difficulty_param->alternatives[1] = DIFFICULTY_NORMAL;
difficulty_param->alternatives[2] = DIFFICULTY_HARD;
difficulty_param->alternatives_number = 3;
settings_difficulty = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(settings_difficulty->title, "Difficulty");
settings_difficulty->submenu_pages[0] = NULL;
settings_difficulty->parent_menu_page = NULL;
settings_difficulty->submenu_pages_number = 0;
settings_difficulty->setting = &difficulty_param;
menu_setting = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(menu_setting->title, "Settings");
menu_setting->submenu_pages[0] = controller_layout;
menu_setting->submenu_pages[1] = settings_difficulty;
menu_setting->submenu_pages[2] = settings_advanced;
//printf("Child 1 before: %d, %d",menu_setting->submenu_pages[0], controller_layout);
menu_setting->parent_menu_page = NULL;
menu_setting->submenu_pages_number = 3;
menu_setting->setting = NULL;
menu_setting = menu_page_address_offset;
menu_page_address_offset += 1;
main_menu = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(main_menu->title, "Main Menu");
main_menu->submenu_pages[0] = start_game;
main_menu->submenu_pages[1] = menu_setting;
main_menu->parent_menu_page = NULL;
main_menu->submenu_pages_number = 2;
main_menu->setting = NULL;
menu_assign_parents(&main_menu);
}
Data memory usage incereases from 82% to 102% with these additional declarations. I assume it should take less space? What am I doing wrong?
In this case, the it was unneccessary to hold the pointers in data memory, so I changed them to be temporary in the init()-function. Instead of keeping the pointers I chose to create a menu_page** table to hold the pointers in SRAM-memory.
relevant info in new header:
typedef enum {
//Run status flag for the game (Turn on/off):
GAME_STATUS,
//Holds possible parameters for solenoid control selection:
SOLENOID_PARAMETERS,
//Holds possible parameters for servo control selection:
SERVO_PARAMETERS,
//Holds possible parameters for motor control selection:
MOTOR_PARAMETERS,
//Holds possible parameters for difficulty:
DIFFICULTY_PARAMETERS,
GAME_SETTING_ELEMENTS = 5 // <-Has to be adjusted to number of elements in this enum!
}game_setting_data_index;
typedef enum {
//Pressing this option starts the game:
START_GAME,
//Menu for configuring which button to control solenoid:
SOLENOID_CONTROL,
// -||- which adc to control servo:
SERVO_CONTROL,
// -||- control motor:
MOTOR_CONTROL,
// Parent page for controller-configuration:
CONTROLLER_LAYOUT,
//More settings for the game:
SETTINGS_ADVANCED,
//Set difficulty:
SETTINGS_DIFFIULTY,
//Parent page for all settings, has previous pages as children:
MENU_SETTING,
MAIN_MENU,
MENU_PAGE_ELEMENTS = 9 //<--Has to be adjusted to number of elements in this enum!
}menu_page_data_index;
New init-function:
void menu_init()
{
const volatile menu_page* MENU_PAGE_SRAM_BASE_OFFSET = 0x1C01;
const volatile menu_page* GAME_SETTING_SRAM_BASE_OFFSET = 0x1E01;
//The menu_pages will be stored right after the last menu_page_address in SRAM_memory:
menu_page* menu_page_address_offset = MENU_PAGE_SRAM_BASE_OFFSET;
game_setting* game_setting_address_offset = GAME_SETTING_SRAM_BASE_OFFSET;
game_setting* game_status = game_setting_address_offset;
game_setting_address_offset += 1;
game_status->parameter = &game_parameters_array[RUN_STATUS];
game_status->alternatives[0] = OFF;
game_status->alternatives[1] = ON;
game_status->alternatives_number = 2;
menu_page* start_game = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&start_game->title, "Start game");
start_game->submenu_pages[0] = NULL;
start_game->parent_menu_page = NULL;
start_game->submenu_pages_number = 0;
start_game->setting = &game_status;
game_setting* solenoid_param = game_setting_address_offset;
game_setting_address_offset += 1;
solenoid_param->parameter = &game_parameters_array[SOLENOID];
solenoid_param->alternatives[0] = X_POSITION;
solenoid_param->alternatives[1] = Y_POSITION;
solenoid_param->alternatives[2] = LEFT_SLIDER;
solenoid_param->alternatives[3] = RIGHT_SLIDER;
solenoid_param->alternatives_number = 4;
menu_page* solenoid_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&solenoid_control->title,"Solenoid");
solenoid_control->submenu_pages[0] = NULL;
solenoid_control->parent_menu_page = NULL;
solenoid_control->submenu_pages_number = 0;
solenoid_control->setting = &solenoid_param;
game_setting* servo_param = game_setting_address_offset;
game_setting_address_offset += 1;
servo_param->parameter = &game_parameters_array[SERVO];
servo_param->alternatives[0] = X_POSITION;
servo_param->alternatives[1] = Y_POSITION;
servo_param->alternatives[2] = LEFT_SLIDER;
servo_param->alternatives[3] = RIGHT_SLIDER;
servo_param->alternatives_number = 4;
menu_page* servo_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&servo_control->title, "Servo");
servo_control->submenu_pages[0] = NULL;
servo_control->parent_menu_page = NULL;
servo_control->submenu_pages_number = 0;
servo_control->setting = &servo_param;
game_setting* motor_param = game_setting_address_offset;
game_setting_address_offset += 1;
motor_param->parameter = &game_parameters_array[MOTOR];
motor_param->alternatives[0] = X_POSITION;
motor_param->alternatives[1] = Y_POSITION;
motor_param->alternatives[2] = LEFT_SLIDER;
motor_param->alternatives[3] = RIGHT_SLIDER;
menu_page* motor_control = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(&motor_control->title, "Motor");
motor_control->submenu_pages[0] = NULL;
motor_control->parent_menu_page = NULL;
motor_control->submenu_pages_number = 0;
motor_control->setting = &motor_param;
#ifdef OLED_MENU_INIT_DEBUG
printf("Menu Title: %s\n", motor_control->title);
#endif
menu_page* controller_layout = menu_page_address_offset;
//printf("Controller_layout addr: , %d\n", (int)menu_page_address_offset);
menu_page_address_offset += 1;
strcpy(controller_layout->title, "Controller Layout");
controller_layout->submenu_pages[0] = motor_control;
printf("motor_control : %X\n", motor_control);
controller_layout->submenu_pages[1] = servo_control;
controller_layout->submenu_pages[2] = solenoid_control;
controller_layout->parent_menu_page = NULL;
controller_layout->submenu_pages_number = 3;
controller_layout->setting = NULL;
menu_page* settings_advanced = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(settings_advanced->title, "Advanced Settings");
settings_advanced->submenu_pages[0] = NULL;
settings_advanced->parent_menu_page = NULL;
settings_advanced->submenu_pages_number = 0;
settings_advanced->setting = NULL;
game_setting* difficulty_param = game_setting_address_offset;
game_setting_address_offset += 1;
difficulty_param->parameter = &game_parameters_array[DIFFICULTY];
difficulty_param->alternatives[0] = DIFFICULTY_EASY;
difficulty_param->alternatives[1] = DIFFICULTY_NORMAL;
difficulty_param->alternatives[2] = DIFFICULTY_HARD;
difficulty_param->alternatives_number = 3;
menu_page* settings_difficulty = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(settings_difficulty->title, "Difficulty");
settings_difficulty->submenu_pages[0] = NULL;
settings_difficulty->parent_menu_page = NULL;
settings_difficulty->submenu_pages_number = 0;
settings_difficulty->setting = &difficulty_param;
menu_page *menu_setting = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(menu_setting->title, "Settings");
menu_setting->submenu_pages[0] = controller_layout;
menu_setting->submenu_pages[1] = settings_difficulty;
menu_setting->submenu_pages[2] = settings_advanced;
//printf("Child 1 before: %d, %d",menu_setting->submenu_pages[0], controller_layout);
menu_setting->parent_menu_page = NULL;
menu_setting->submenu_pages_number = 3;
menu_setting->setting = NULL;
menu_setting = menu_page_address_offset;
menu_page_address_offset += 1;
menu_page* main_menu = menu_page_address_offset;
menu_page_address_offset += 1;
strcpy(main_menu->title, "Main Menu");
main_menu->submenu_pages[0] = start_game;
main_menu->submenu_pages[1] = menu_setting;
main_menu->parent_menu_page = NULL;
main_menu->submenu_pages_number = 2;
main_menu->setting = NULL;
//menu_assign_parents(&main_menu);
printf("Offsets: menupage: %X, game_setting: %X\n", menu_page_address_offset, game_setting_address_offset);
printf("Bytes per page: %d, %d\n", sizeof(menu_page), ((int)menu_page_address_offset-0x1C01)/10);
//Create address table at end of menu_page entries:
menu_page_address_table = menu_page_address_offset;
//Create address table at end of game_setting entries:
game_setting_address_table = game_setting_address_offset;
/*Game settings and pages have been placed in the order
of the menu_page_data_index-enum, address-tables should
be updated accordingly: */
printf("Menu address table: \n");
for (int i; i < MENU_PAGE_ELEMENTS; i++)
{
menu_page_address_table[i] = MENU_PAGE_SRAM_BASE_OFFSET + i;
printf("%X ", menu_page_address_table[i]);
}
printf("\nGame setting address table: \n");
for (int i; i < GAME_SETTING_ELEMENTS; i++)
{
game_setting_address_table[i] = GAME_SETTING_SRAM_BASE_OFFSET + i;
printf("%X ", game_setting_address_table[i]);
}
printf("\n");
}
Initializing each struct member seems a bit unneccessary, I'm gonna try to create an init-function for each struct instead.