Advice on interdependent asynchronous functions and task queuing?
-
I am working with embedded programming in standard C and there are 2 microcontrollers communicating with each other using a home-made SPI-protocol. In addition, microcontroller 2 has a CAN-bus that should also (indirectly) be fully accessible from microcontroller 1. The scheduler and task queues are also home-made so no realtime operating system is used. My tasks look like this:
void (*task_t)(uint8_t* taskData, uint16_t sizeOfTaskDataInBytes);
My functions to add 1 or 2 tasks look like this:
typedef enum {
TASK_IN_WAIT_PHASE = 0,
TASK_FINISHED = 1
} taskStatus_e;typedef taskStatus_e (*getTaskStatusCallback_t)(uint8_t* data, uint16_t dataSizeBytes);
Bool_t queueTask(taskQueueSelector_e, task_t, uint8_t* data, uint16_t dataSizeBytes, getTaskStatusCallback_t);
Bool_t queue2Tasks(taskQueueSelector_e, task_t task1, uint8_t* data1, uint16_t data1SizeBytes, getTaskStatusCallback_t getTaskStatusCallback1, task_t task2, uint8_t* data2, uint16_t data2SizeBytes, getTaskStatusCallback_t getTaskStatusCallback2);When microcontroller 1 wants to read from microcontroller 2 over SPI, the following code is used:
struct SPI_secretData_s {
volatile Bool_t accessInProgress;
volatile int8_t numRetriesLeft;
};#define PLEASE_SEE_NUM_REGS_TO_ACCESS_PARAMETER (1)
struct SPI_readRegsTaskParams_s {
struct SPI_secretData_s secretData;
volatile uint32_t startAddr;
volatile uint16_t numRegsToAccess;
volatile SPI_readStatus_e readStatus;
volatile uint16_t readBuffer[PLEASE_SEE_NUM_REGS_TO_ACCESS_PARAMETER];
};queue2Tasks(SPI_QUEUE_SELECTOR, SPI_readRegs, (uint8_t*)&SPI_readRegsTaskParams, sizeof(SPI_readRegsTaskParams), SPI_getTaskStatusCallback, SPI_handleReadIsFinished, NULL, 0, NULL);
taskStatus_e SPI_getTaskStatusCallback(uint8_t* data, uint16_t dataSizeBytes) {
struct SPI_readRegsTaskParams_s* SPI_readRegsTaskParams = (struct SPI_readRegsTaskParams_s*)data;
return (SPI_readRegsTaskParams->secretData.accessInProgress) ? TASK_IN_WAIT_PHASE : TASK_FINISHED;
}uint32_t SPI_handleReadIsFinished(uint8_t* notUsed, uint16_t sizeOfNotUsedInBytes) {
struct SPI_readRegsTaskParams_s* SPI_readRegsTaskParams = (struct SPI_readRegsTaskParams_s*)getPreviousTaskData();
//... Do what you need to do with the read data...
}When microcontroller 2 wants to read from the CAN-bu
-
I am working with embedded programming in standard C and there are 2 microcontrollers communicating with each other using a home-made SPI-protocol. In addition, microcontroller 2 has a CAN-bus that should also (indirectly) be fully accessible from microcontroller 1. The scheduler and task queues are also home-made so no realtime operating system is used. My tasks look like this:
void (*task_t)(uint8_t* taskData, uint16_t sizeOfTaskDataInBytes);
My functions to add 1 or 2 tasks look like this:
typedef enum {
TASK_IN_WAIT_PHASE = 0,
TASK_FINISHED = 1
} taskStatus_e;typedef taskStatus_e (*getTaskStatusCallback_t)(uint8_t* data, uint16_t dataSizeBytes);
Bool_t queueTask(taskQueueSelector_e, task_t, uint8_t* data, uint16_t dataSizeBytes, getTaskStatusCallback_t);
Bool_t queue2Tasks(taskQueueSelector_e, task_t task1, uint8_t* data1, uint16_t data1SizeBytes, getTaskStatusCallback_t getTaskStatusCallback1, task_t task2, uint8_t* data2, uint16_t data2SizeBytes, getTaskStatusCallback_t getTaskStatusCallback2);When microcontroller 1 wants to read from microcontroller 2 over SPI, the following code is used:
struct SPI_secretData_s {
volatile Bool_t accessInProgress;
volatile int8_t numRetriesLeft;
};#define PLEASE_SEE_NUM_REGS_TO_ACCESS_PARAMETER (1)
struct SPI_readRegsTaskParams_s {
struct SPI_secretData_s secretData;
volatile uint32_t startAddr;
volatile uint16_t numRegsToAccess;
volatile SPI_readStatus_e readStatus;
volatile uint16_t readBuffer[PLEASE_SEE_NUM_REGS_TO_ACCESS_PARAMETER];
};queue2Tasks(SPI_QUEUE_SELECTOR, SPI_readRegs, (uint8_t*)&SPI_readRegsTaskParams, sizeof(SPI_readRegsTaskParams), SPI_getTaskStatusCallback, SPI_handleReadIsFinished, NULL, 0, NULL);
taskStatus_e SPI_getTaskStatusCallback(uint8_t* data, uint16_t dataSizeBytes) {
struct SPI_readRegsTaskParams_s* SPI_readRegsTaskParams = (struct SPI_readRegsTaskParams_s*)data;
return (SPI_readRegsTaskParams->secretData.accessInProgress) ? TASK_IN_WAIT_PHASE : TASK_FINISHED;
}uint32_t SPI_handleReadIsFinished(uint8_t* notUsed, uint16_t sizeOfNotUsedInBytes) {
struct SPI_readRegsTaskParams_s* SPI_readRegsTaskParams = (struct SPI_readRegsTaskParams_s*)getPreviousTaskData();
//... Do what you need to do with the read data...
}When microcontroller 2 wants to read from the CAN-bu
Just like I have a secretData_s struct as part of the task data, maybe I should also have a postTaskInfo_s section:
#define PLEASE_SEE_SIZE_OF_POST_TASK_DATA_PARAMETER (1)
struct postTaskInfo_s {
task_t postTask;
taskQueueSelector_e postTaskQueueSelector;
uint16_t sizeOfPostTaskData;
uint8_t postTaskData[PLEASE_SEE_SIZE_OF_POST_TASK_DATA_PARAMETER]
};Then if postTaskInfo->postTask is not null then the CAN_readRegs-task will queue the postTask just before it's finished. Can someone think of something better?