FreeRTOS task from within a class is only partially working

I’ve created a FreeRTOS task to be started from within a class.
Code is here:
https://github.com/Aleph-Design/FreeRTOS_CPP_Class_01

Question:
The code as is in GitHub, works great.
But the code commented out indicated by ‘MARK’ does not.
Just what am I missing here?

The error you get is

src\main.cpp: In function 'void setup()':
src\main.cpp:19:10: error: 'class Led' has no member named 'ledMain'
   ledOne.ledMain();
          ^

This is because there is no member function called ledMain() in the class, or the class it inherits from. (See here).

You slightly misunderstood how the class was programmed and intended to use. You see in the base class you have

This implements the constructor. So as soon as the object is constructed it will call xTaskCreatePinnedToCore () to create a new task with the entry function blinkLed() and with this as the argument.

Then

and as discussed void *pvParam is this (the pointer to the object that was created), but type-erased through the void pointer. Here it’s casted back to the original type, BaseTask and then the main() function is called on it.

You then see in the derived class

it is doing a initializer list where it calls into the BaseTask constructor, then initilaizes hte _ledPin and _ticks memebr variables, then calls pinMode.

Finally, the main() function has been overwritten to

do the blinky code.

So what will happen is if you creat a Led object, the constructor call will automatically cause the creation of the task and start running it as soon as possible. So there is no “start” function for you to call because it was not implemented that way.

You also have to take care to not destruct the object. E.g., if the object was created on the stack of a function, and execution leaves that function, all the variables defined inside that function are destroyed. So e.g. doing it like

#include <Arduino.h>
#include <ledApp.h>

void setup() 
{
  Led ledOne(1024, 1, "Blink Led", LED_PIN, 750);
  /* more code.. */
}

void loop() { /* code */ }

(and not having any other global variable) would be wrong because once setup() has finisihed executing, the ledOne variable will be destructed, and then you have a FreeRTOS task still accessing memory of a destructed object, which is a bug (memory corruption will occur once other variables are allocated on the stack). This is very dangerous because the above code would compile but result in a bug.

The original code already shows the right way of doing it. Allocating it as a global variable

#include <Arduino.h>
#include <ledApp.h>

Led ledOne(1024, 1, "Blink Led", LED_PIN, 750);

void setup() 
{
  /* more code.. */
}

void loop() { /* code */ }

will make it so that the ledOne object, which is a global variable, will be constructed in the global context (this even happens before the main() function of Arduino is called), and in the constructor it will create a new thread, that is then executed automatically once Arduino initialization has progressed further. No need to call any functions further on the object.

Another possible way is to create the object dynamically on the heap using new. Then it will not be destructed until delete is explicitly used on the object.

So what you can do is

#include <Arduino.h>
#include <ledApp.h>

Led* pLedOne;

void setup() 
{
   /* construct object using heap memory */
   pLedOne = new Led(1024, 1, "Blink Led", LED_PIN, 750);
}

void loop() { }

At some later time in the firmware then you can use the pLedOne pointer to still access some (future implemented) member functions if you need to – none are implemented as of now. You can also call delete pLedOne; to de-allocate the object. However, with the current implementation, that will lead to a bug since the destructor, ~BaseTask (), is not implemented, so it will do nothing. Here, code should be placed to terminate the task pointed to by taskHandle (vTaskDelete() or a synchronization / signaling mechanism in the task code lets it terminate itself). But if one does not need the functionality of stopping that task ever, that is not needed.

1 Like

Maximilian,
Thank you. It took me some time to digest what you are telling me.
This: “because once setup() has finished executing, the ledOne variable will be destructed”, was the eye opener.