I am trying to make a base class that holds a semaphore and wait until it can take the semaphore and then call a function in a derived class. (I want to have a number of different base classes that implement the function different but all of them schuld execute this function only after acquiring the semaphore. I am not very familiar with freertos, so i think probably the error is related to that.
I made some attempts but so far with no success.
Here is the basic code:
The Base class:
class CommandMode{
public:
CommandMode(xSemaphoreHandle* smphr_calc_steps);
virtual ~CommandMode(){};
virtual int GetNextState()=0;
protected:
static void TSK_CalcSteps(void* params);
xSemaphoreHandle* smphr_calc_steps;
virtual void CalculateSteps(){};
};
CommandMode::CommandMode(xSemaphoreHandle* smphr_calc_steps):smphr_calc_steps(smphr_calc_steps){
xTaskCreate(&TSK_CalcSteps, "output data calc", 2048, this, 1, NULL);
}
void CommandMode::TSK_CalcSteps(void* params){
CommandMode* cm = (CommandMode*) params;
while(true){
//force reevaluation at least every 60s
xSemaphoreTake(cm->smphr_calc_steps, 60*1000/portTICK_PERIOD_MS); // i think the problem is related to that line
cm->CalculateSteps();
}
}
and here the derived class:
class Mode1:public CommandMode{
public:
Mode1(xSemaphoreHandle* smphr_calc_steps);
~Mode1(){};
int GetNextState() override;
protected:
void CalculateSteps() override;
};
Mode1::Mode1(xSemaphoreHandle* smphr_calc_steps) : CommandMode(smphr_calc_steps){}
void Mode1::CalculateSteps(){
Serial.println("Mode1::CalculateSteps");
}
int Mode1::GetNextState(){
Serial.println("Mode1::GetNextState");
return 5;
}
Then i try to invoke them similar to this:
CommandMode* current = nullptr;
xSemaphoreHandle smphr = xSemaphoreCreateBinary();
//xSemaphoreHandle smphr2 = xSemaphoreCreateBinary();
Serial.println("init with mode1");
delay(200);
Mode1* a = new Mode1(&smphr);
a->GetNextState(); //This will work
current = a;
current->GetNextState(); //This will work as well
xSemaphoreGive(smphr); //This does not work as intended/causes the issue
Im also not sure about the line cm->CalculateStepes(). Since i passed 'cm' as a void* will it still be evaluating the correct subclass's module? I am running this on an ESP32 with Plattform IO in case this is important.
So far i sometimes got a watchdog error, but mostly i get the following two errors:
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c:1443 (xQueueGenericReceive)- assert failed!
abort() was called at PC 0x40087f1d on core 0
assertion "res == coreID || res == portMUX_FREE_VAL" failed: file "/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/portmux_impl.inc.h", line 105, function: vPortCPUAcquireMutexIntsDisabledInternal
abort() was called at PC 0x400d8cf3 on core 0
I tried use the whole code out of a task itself and experimented with multiple delays(), but I never got it working.
I would be glad if someone could tell me where the problem is, or has a suggestion how to implement this behavior in a better way? I want to have other functions and values in the base class as well. This works without a problem but the calling of the derived class's function based upon the semaphore is not working at all.
xSemaphoreTake
expects the handle to be passed by value, you pass it by pointer, that is definitely wrong.
The code compiles because SemaphoreHandle_t
itself is a hidden pointer (hence this not being a good practice, but occurs often in low-level stuff for other good reasons). This also means that you can and should pass and store smphr_calc_steps
as a value in your class, being a pointer its cheap to copy. The extra indirection is not needed and only complicates stuff.
FreeRTOS allocates the semaphore on the heap and returns a pointer(=the handle) to you, your only responsibility is to call vSemaphoreDelete
sometime in the future to free up the memory.