Hello all,
I have two tasks doing the same job on different data and hardware peripherals. Now I think of making a class for this. But how can I create the tasks and give each the function of one class instance? Something like this:
This fails to compile because the function signature does not match.
How to do it? The pointer needed for a TaskFunction_t could be the this pointer of a class member function.
Normally you do this kind of thing by having a dispatcher function as the task function. You pass the this pointer of your class instance as the task parameter, and the dispatcher then invokes your instance’s task_main_func member via the coerced instance pointer.
Yours is shorter but more tricky to understand (I think). But if you have more than 2 identical tasks, yours is surely better.
Just to be sure:
Either entry function is called only once when the tasks enters running state for the first time, right? After that the current program position is recalled and the entry function play no more roll.
Thanks
Martin
I’m not quite sure I understand what you are getting at here. When you break into, say, somewhere into my_class.task_main_func(), your debugger will of course remember the full call stack down to either of your task_main_func or (in my case) the dispatcher fn, but (assuming your my_class.task_main_func() never returns, which is the normal and regular behavior), control flow never unwinds to the “shell” function.
Your solution isx perfectly ok. As you suggest, mine comes in handy when there is a variable number of instances. Say, for example, that your application is a communication server where you can activate a configuration dependent number of serial ports at runtime. In such a case, you typically have a class that represents a serial port and that has a thread fn as a member. In that use case, it is an advantage not to have to pass a task fn into xTaskCreateStatic() that is linked to the instance but a generic function.
The DispatcherFn is doing the job. However, this function must be made for every Class-Member combination. Is it possible to make the DispatcherFn evenmore general so that the class and the member can be given as an argument ( via a struct ?)
I do not think you can pass type as argument but you can make a base class and all the class with task entry point can derive from that class. That way you’ll be able to have one DispatcherFn:
This is a very good idea and solves my question. Thank you.
below i add the code example (main.cpp with the task creation, taskBaseClass.h with the baseClass, testClassh and testClass.cpp )
//main.cpp
#include <Arduino.h>
#include "testclass.h"
// create Dispatcher
void DispatcherFn(void *arg)
{
taskBaseClass *x = (taskBaseClass *)arg;
x->loadConfig();
x->mainTaskFunction();
}
// instantiate classes
testClass test01(8, 1000, "test1000");
testClass test02(222, 2100, "test2100");
void setup()
{
Serial.begin(115200);
Serial.println("Start");
// launch task
xTaskCreate( //
DispatcherFn, /* Task function. */
"task_class_01", /* String with name of task. */
10000, /* Stack size in bytes. */
&test01, /* Parameter passed as input of the task */
1, /* Priority of the task. */
NULL); /* Task handle. */
xTaskCreate( //
DispatcherFn, /* Task function. */
"task_class_02", /* String with name of task. */
10000, /* Stack size in bytes. */
&test02, /* Parameter passed as input of the task */
1, /* Priority of the task. */
NULL);
}
void loop()
{
// put your main code here, to run repeatedly:
}
#ifndef TESTCLASS_H
#define TESTCLASS_H
#include <Arduino.h>
#include "taskBaseClass.h"
class testClass: public taskBaseClass
{
public:
int val1, del, som;
char *pcTaskName;
String str;
//constructors
testClass(int _val1,int _del, String _str)
{
val1 = _val1;
str=_str;
del=_del;
}
//methods
// loadConfig() and mainTaskFunction() are pure virtual functions
// they will be defined in the class cpp file
// loadconfig takes care of initilazing the class variables,
// eventually reading from a file, ex: reading parameters from a sensor
void loadConfig() override;
// mainTaskFunction is the main loop of the class ex: read a sensor
void mainTaskFunction() override;
};
#endif