I have implemented a queue in C language with usage of an array of structures.
typedef struct{
req_t buffer[BUFFER_SIZE]; // buffer
uint16_t size; // length of the queue
uint16_t count; // number of elements present in the queue
req_t *p_head; // pointer to head of the queue (read end)
req_t *p_tail; // pointer to tail of the queue (write end)
}circular_buffer_t;
void init_cb(circular_buffer_t *p_cb){
p_cb->p_head = p_cb->buffer;
p_cb->p_tail = p_cb->buffer;
p_cb->count = 0;
p_cb->size = BUFFER_SIZE;
}
The problem is that above given implementation is usable only for storing the instances of req_t structures. Now I need to store instances of another structure and I don't know how to define the queue in more general way so that I will be able to use same queue for instances of different structures. Problem is that I need to know the structure type before buffer definition. Does anybody have any idea how to solve that?
#ifndef CIRCULAR_BUFFER_H_
#define CIRCULAR_BUFFER_H_
#define BUFFER_SIZE 32
// macro creates variant of the queue for each struct type
#define define_queue(TYPE) \
\
// queue element definition \
typedef struct{ \
TYPE buffer[BUFFER_SIZE]; \
uint16_t size; \
uint16_t count; \
TYPE *p_head; \
TYPE *p_tail; \
}circular_buffer_##TYPE##_t \
\
\
// queue init function definition \
void init_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb){ \
p_cb->p_head = p_cb->buffer; \
p_cb->p_tail = p_cb->buffer; \
p_cb->count = 0; \
p_cb->size = BUFFER_SIZE; \
} \
\
// queue enqueue function definition \
BOOL enqueue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE *p_enq_elem){ \
\
if(p_cb->count < p_cb->size){ \
\
taskENTER_CRITICAL(); \
\
*(p_cb->p_tail) = *p_enq_elem; \
p_cb->p_tail = ((++(p_cb->p_tail) == (p_cb->buffer + p_cb->size)) ? \
(p_cb->buffer) : (p_cb->p_tail)); \
p_cb->count++; \
\
taskEXIT_CRITICAL(); \
\
return TRUE; \
\
}else{ \
\
return FALSE; \
\
} \
\
} \
\
// queue dequeue function definition \
BOOL dequeue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE *p_deq_elem){ \
\
if((p_cb->count) != 0){ \
\
taskENTER_CRITICAL(); \
\
*p_deq_elem = *(p_cb->p_head); \
p_cb->p_head = ((++(p_cb->p_head) == (p_cb->buffer + p_cb->size)) ? \
(p_cb->buffer) : (p_cb->p_head)); \
p_cb->count--; \
\
taskEXIT_CRITICAL(); \
\
return TRUE; \
\
}else{ \
\
return FALSE; \
\
} \
\
} \
// macros for functions declarations
#define declare_init_cb(TYPE) void init_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb)
#define declare_enqueue_cb(TYPE) BOOL enqueue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE p_enq_elem);
#define declare_dequeue_cb(TYPE) BOOL dequeue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE p_deq_elem);
#endif
Structures I am going to use with the queue
typedef struct{
uint32_t addr; // address of the alarm signal
BOOL critical; // alarm is critical (=TRUE), alarm is non critical (=FALSE)
BOOL set; // alarm was set (=TRUE)
BOOL cleared; // alarm was cleared (=TRUE)
BOOL communicated; // alarm is communicated to Main Controller (=TRUE)
uint8_t code; // alarm code (0 - 255) - permanently 180
uint8_t no; // alarm number (0 - 255)
uint8_t no_flashes; // number of LED flashes if the alarm is active
}alarm_t;
and
typedef struct{
msg_e req_type; // request type
uint8_t blk_no; // block number
uint8_t no_records; // number of influenced records
uint8_t data_id[MAX_NO_RECORDS]; // data id, max. number of records in one block
uint16_t value[MAX_NO_RECORDS]; // written value, max. number of records in one block
uint8_t cleared_alarm_no; // number of the alarm which should be cleared
uint8_t flash_load; // 0 = Go into flash load mode
uint8_t mode[6]; // 000000 - Normal, BOOTBL - Boot block
uint8_t data_block[BLOCK_SIZE]; // one block in flash memory
uint8_t flash_page_number; // page number in flash memory (starting at 1)
uint8_t flash_block_number; // block number in flash memory (starting at 1)
}req_t;
req_tdata type?memcpy()andvoid *to implement storing and accessing.unionis usually what you want. It's like astruct, but with all members starting at the same offset. The size of the union is determined by the size of the largest member. In this case, however, you also need some indicator in each queue slot which determines which type is stored there.