Esp32-snippets: Explanation/example of using cpp_utils Task class

Created on 9 Dec 2017  路  7Comments  路  Source: nkolban/esp32-snippets

Trying to implement the Task class but having trouble figuring out how to use it and get it to compile - seems that I don't declare a task class instance in the 'normal' fashion, i.e. Task task1;

Do you have a simple example you could point me to?

Also, am I able to use a class object function as a task? I've been trying to determine how to create tasks that have access to class instances - so far I've only been able to get static function tasks working...

question waiting

Most helpful comment

To create a Task class, one would code:

#include <Task.h>
class MyTask: public Task {
   void run(void *data) {
      // do something
   }
}

and then to run the task, one would code:

MyTask* pMyTask = new MyTask();
pMyTask->start();

The coding style you are finding (and maybe the one you are having troubles with) is the C++ concept of class inheritance. See:

http://www.geeksforgeeks.org/inheritance-in-c/

The notion of inheritance is that we have a "base" class that contains common code but doesn't do "exactly" what you want. You then create an inheritance from this which creates a new class that inherits and exposes what was found in the base class plus what you have exposed in your parent class.

Sometimes a base class is defined as not in-stantiable but merely serves as a template (these are called abstract classes). For example ... Imagine a class called "Car" that defines the nature of a car ... however, we don't drive "generic" cars ... instead we drive instances of models of cars ... for example:

class ToyotaCorrolla: public Car

Defines a new class called a ToyotaCorrolla which does everything a Car does but is specialized for that particular brand.

All 7 comments

To create a Task class, one would code:

#include <Task.h>
class MyTask: public Task {
   void run(void *data) {
      // do something
   }
}

and then to run the task, one would code:

MyTask* pMyTask = new MyTask();
pMyTask->start();

The coding style you are finding (and maybe the one you are having troubles with) is the C++ concept of class inheritance. See:

http://www.geeksforgeeks.org/inheritance-in-c/

The notion of inheritance is that we have a "base" class that contains common code but doesn't do "exactly" what you want. You then create an inheritance from this which creates a new class that inherits and exposes what was found in the base class plus what you have exposed in your parent class.

Sometimes a base class is defined as not in-stantiable but merely serves as a template (these are called abstract classes). For example ... Imagine a class called "Car" that defines the nature of a car ... however, we don't drive "generic" cars ... instead we drive instances of models of cars ... for example:

class ToyotaCorrolla: public Car

Defines a new class called a ToyotaCorrolla which does everything a Car does but is specialized for that particular brand.

thanks. I understand the inheritance issue. Don't quite understand how to get around some of the access issues without declaring global instance variables/pointers. Having similar difficulties when using other callbacks like wifievents as well. Hopefully with this explanation and your additional comments (#207), I'll be set to go.

Ive got this problem trying to pass member function as interruption callback. Maybe this will help you to understand the problem:
https://isocpp.org/wiki/faq/pointers-to-members

Simply put, you can't pass a member function of a C++ class as a C style callback. Here is why.

Imagine you have a function that reads:

void doMyWork((callback*)(int)) {
  // Do something
  callback(result);
}

Now to use this, you might code:

void myCallback(int x) {
  // Do something with callback
}

...
doMyWork(myCallback);

Hopefully this is all clear and, if not ... pause and hit some books on this area. The remainder assumes you understand C function references and invoking them.

Now imagine you have a class:

class MyClass {
public:
  void myCallback(int x) {
    // Do something with callback
  }
}
...
MyClass myClass;
doMyWork(myClass.myCallback);  // This won't work

To understand why it won't work, understand that a callback function is "just" a pointer to a memory location that is invoked when the callback is invoked. It is a GoTo to a piece of code. However, invoking a C++ method is NOT the same as invoking a memory location ... because a method in a C++ class has context. The method being invoked in the C++ class executes in the context of the C++ class instances in which it is called (with the exception of static methods that have no context).

You are having puzzles because we are working in a mixed programming environment. The ESP-IDF is a C based environment where-as we are doing other work in a C++ environment. They can safely be used together, you just have to play by the rules. And one of the rules is that passing a pointer to a member function of a C++ class doesn't result in anything useful.

sorry, I seem to be bouncing between this and issue #207.

So, with callback (which may be off-topic to original), like WifiEventHandler, in order to access class instance functions (again without global object), would I need to monitor something like EventGroupHandle in a separate task in order to respond with class methods to a callback event?

If what you want to do is invoke a method in an instance of a class when a global event happens, then you would register a non-class instance function to be invoked as a callback for the event. In that function, you would then need addressability to the instance of the class that you want to call and then invoke it through the reference to the class.

go it. that was the conclusion I was coming to - thanks for the clarification

Was this page helpful?
0 / 5 - 0 ratings