Lately I am having a lot of trouble with C++ and understanding static functions. I think I found a really elegant way to mix both concenpts: FreeRTOS and dinamic memory with OOP.
I was inspired by this CPP code that do that pretty nice.
Here is my code:
/*
This file contains the code for executing on the incoming commands from MC
*/
#include <Arduino.h>
#include <executor/Executor.h>
#include "sbcPacket/sbcPacket.h"
/* Constructor Set parameters*/
Executor::Executor(LoadSwitch* loadSwitches, Delayer* delayer){
this->loadSwitches = loadSwitches;
this->delayer = delayer;
// Create FreeRTOS semaphore and task
_asq_sem = xSemaphoreCreateBinary();
_runSequenceTask = xTaskCreate(
Executor::runSequenceHandlerTask,
"runSequenceHandlerTask",
500,
this,
2,
&runSequencetaskHandle
);
configASSERT(_runSequenceTask);
}
void Executor::RunCommand(const uint8_t *buffer, size_t length) {
...
}
void Executor::runSequence(){
while (true) {
if (xSemaphoreTake(_asq_sem, portMAX_DELAY) == pdTRUE) {
for (int i = 0; i < _sequenceLength; i++) {
...
RunCommand(command, size);
}
}
}
}
void Executor::runSequenceHandlerTask(void* instance){
auto* app = static_cast<Executor*>(instance);
app->runSequence();
}
void Executor::startSequence(){
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(_asq_sem, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
#ifndef EXECUTOR_H
#define EXECUTOR_H
#include <STM32FreeRTOS.h>
#include "bControllable/bControllable.h"
#include "loadSwitch/loadSwitch.h"
#include "delayer/delayer.h"
#define SEQ_MAX_LENGTH 50
class Executor {
LoadSwitch* loadSwitches;
Delayer* delayer;
public:
Executor(LoadSwitch* LoadSwitches, Delayer* delayer);
void RunCommand(const uint8_t *buffer, size_t length); // probably there will be more overloaded versions of RunCommand
void buildSequence(const uint8_t *buffer, size_t bufferLength); // For building the autosequence
void startSequence(); // Start the saved autosequence
void runSequence();
private:
// List of the dynamic arrays that are used to contain the autosequence
int _asqControllablesArray[SEQ_MAX_LENGTH] = {0};
int _asqValueArray[SEQ_MAX_LENGTH] = {0};
int _sequenceLength = 0;
static void runSequenceHandlerTask(void* instance);
SemaphoreHandle_t _asq_sem; // Semaphore used for executing the autosequence
portBASE_TYPE _runSequenceTask;
TaskHandle_t runSequencetaskHandle;
};
#endif /* EXECUTOR_H */
If you dont want to analize the code. Basically is that you are passing the object (this) as a parameter to FreeRTOS, and then to run the functions. So the HandlerTask is static, but accessign dynamic objects. For doing this is necessary to use a TaskHandle_t.