Functions without parameters
Let begin from the easiest one: the queues for function pointers without parameters.
A definition:
//-8<--8<--8<--ANTIRTOS_C BEGIN--8<--8<--8<--8<---
#define fQ(q, Q_SIZE) \
volatile int q##_last = 0; \
int q##_first = 0; \
void (*q##_Queue[Q_SIZE])(void); \
int q##_Push(void (*pointerQ)(void)) { \
if ((q##_last + 1) % Q_SIZE == q##_first)\
return 1; /* Queue is full */ \
q##_Queue[q##_last++] = pointerQ; \
q##_last %= Q_SIZE; \
return 0; /* Success */ \
} \
int (*q##_Pull(void))(void) { \
if (q##_last == q##_first) \
return 1; /* Queue is empty */ \
q##_Queue[q##_first++](); \
q##_first %= Q_SIZE; \
return 0; \
}
//-8<--8<--8<--ANTIRTOS_C END --8<--8<--8<--8<---
Usage:
Define your tasks:
void yourTaskOne(){
//put here what ever you want to execute
}
void yourTaskTwo(){
//put here what ever you want to execute
}
Initialize queues like:
fQ(Q1,8); // define first queue (type fQ) with name Q1, 8 elements length
fQ(Q2,8); // define second queue (type fQ) with name Q2, 8 elements length
......
In main loop:
Q1_Pull(); Q2_Pull(); ...........
In first of your interrupts routines:
void yourInterruptRoutineOne(void){
Q1_Push(yourTaskOne); // just push your task into queue!
}
In second one:
void yourInterruptRoutineTwo(void){
Q2_Push(yourTaskTwo); // just push your task into queue!
}
This is it! Every task is handled. Interrupts kept blazing fast.
The simplicity matter!
Functions with parameters
OK, now it is time to involve parameters if we need them to pass to the functions in queue, let define queue for functions with parameters:
#define fQP(q, Q_SIZE, param_type) \
void (*q##_funcs[Q_SIZE])(param_type); \
param_type q##_params[Q_SIZE]; \
volatile int q##_last = 0; \
int q##_first = 0; \
int q##_Push(void (*func)(param_type), param_type params) { \
if ((q##_last + 1) % Q_SIZE == q##_first) \
return 1; /* Queue is full */ \
q##_funcs[q##_last] = func; \
q##_params[q##_last++] = params; \
q##_last %= Q_SIZE; \
return 0; /* Success */ \
} \
int q##_Pull(void) { \
if (q##_last == q##_first) \
return 1; /* Queue is empty */ \
q##_funcs[q##_first](q##_params[q##_first++]); \
q##_first %= Q_SIZE; \
return 0; /* Success */ \
}
Usage
Define all your tasks:
void blinkLED(int led){
switch(led){
case 0:
HAL_GPIO_TogglePin(LED_YELLOW_PORT, LED_YELLOW_PIN);
break;
case 1:
HAL_GPIO_TogglePin(LED_GREEN_PORT, LED_GREEN_PIN);
break;
}
void printSymbol(char ch){
printf("Number: %c\n", ch);
}
Define all your queues:
fQP(Q1,8,int); //8 elements length, type fQP, functions receive int
fQP(Q2,8,char); //8 elements length, type fQP, functions receive char
In main loop just add:
Q1_Pull(); Q2_Pull();
Where you want just push the tasks into queues and pass them parameters:
Q1_Push(blinkLED, 0);
Q2_Push(printSymbol, 'a');
More parameters
Assume you function require more parameters, just wrap them into your structure, for example:
typedef struct {
int index;
int logic;
} pinout;
So task function will receive here type pinout:
void myTask(pinout p){
// put here what ever you want, your task
}
Now you may initialize your queues, like:
fQP(Q3,8,pinout); //8 elements length, type fQP, functions receive type 'pinout'
You may push parameters now like:
Q3_Push(myTask, (pinout){0,1}); //passing arguments
In main loop as usual:
Q3_Pull();
Interesting Aleksei, I just love simplicity.