arkhipenko / TaskScheduler

Cooperative multitasking for Arduino, ESPx, STM32, nRF and other microcontrollers
http://playground.arduino.cc/Code/TaskScheduler
BSD 3-Clause "New" or "Revised" License
1.33k stars 243 forks source link

Cannot schedule tasks using member functions #89

Closed dratsuc1 closed 4 years ago

dratsuc1 commented 4 years ago

Hi,

I'm following this guide: https://github.com/arkhipenko/TaskScheduler/blob/master/examples/Scheduler_example15_STDFunction/Scheduler_example15_STDFunction.ino#L20

buzzer.h


#include <TaskSchedulerDeclarations.h>

class Buzzer : public IObserver {

public:
    Buzzer();
    Buzzer(int pin, int buzzDuration);
    virtual ~Buzzer();
    void update(Event* newState);
    void startBuzz();
    void stopBuzz();
    Task startBuzzTask;
    Task stopBuzzTask;
private:
    int pin;
    Scheduler runner;
};

buzzer.cpp


Buzzer::Buzzer(int pin, int buzzDuration) {
    this->pin = pin;
    pinMode(this->pin, OUTPUT);

    startBuzzTask(0, TASK_ONCE, [this](){
        this->startBuzz();
    });

    stopBuzzTask(buzzDuration, TASK_ONCE, [this](){
        this->stopBuzz();
    });

    this->runner.init();
    this->runner.addTask(this->startBuzzTask);
    this->runner.addTask(this->stopBuzzTask);
    this->startBuzzTask.enable();
    this->stopBuzzTask.enable();

}

I'm the following error:

error: use of deleted function 'Task& Task::operator=(const Task&)'

I'm not too familiar with C++ to interpret what this means, could it be I'm following legacy practices defining the task like so is deprecated ?

arkhipenko commented 4 years ago

Are you trying to create a Task that turns buzzer on and off depending on the call to update? If that is the intent:

  1. I always use a static instance of scheduler object (one or several if you need layered prioritization). The reason is: the scheduleris a heartbeat of task execution, it lives above all tasks and objects and makes things run. Therefore I do not support hiding schedulers inside classes. All of the above is also the reason why my loop() is always one line: ts. execute() (ts is a static scheduler object)

  2. Example 15 is focused on the use of standard functions, which I think is a kind of lambda function in C++. This example was provided by a contributor. I do not personally use lambdas (nothing wrong with them - jut did not feel the need). So I can't help you there.

  3. I would direct your attention to example 21 for using TS in an object-oriented way.

If I was writing your code I would separate the IObserver and actual Buzzer tasks. I would make Buzzer start buzzing in the OnEnable() method and Stop buzzing in theOnDisable() method. There is no need for the actual callback so that could remain empty. I would implement Buzzer derived from Task class with no additional public methods. You may want to create a private start() and stop() methods and call them from OnEnableand OnDisble respectively. Your IObserver-derived class then just needs to call buzzer.enable() when an enable event arrives and buzzer.disable() when a disable event arrives. A good reference is a SuperSensor class from example 21, but buzzer should be way simpler. Please do not forget to compile with #define _TASK_OO_CALLBACKS compile option.

That's it. Hope this helps.

Regards, Anatoli

arkhipenko commented 4 years ago

And to answer the title of the issue: Cannot schedule tasks using member functions

By default only static callbacks are supported. To enable dynamic method binding you need to compile with _TASK_OO_CALLBACKS option and follow example 21. I do not have the Wiki page for OO method yet. I actually never felt the need to switch to it - the sketches are short enough to use traditional Arduino approach.

dratsuc1 commented 4 years ago

Are you trying to create a Task that turns buzzer on and off depending on the call to update?

The intention of this is to buzz for X seconds without using a delay - this is because i can imagine it causes a block messing up the timings of my scheduled events which may want to run in this time frame. The event class is abstract and will contains an Integer which determines the length to buzz for.

I would make Buzzer start buzzing in the OnEnable() method and Stop buzzing in the OnDisable() method.

I was initially thinking about sending events which say ON / OFF, though that would move my problem to another class of needing a non blocking delay if they had to be run manually, If the OnDisable() is called automatically after the task has run its duration, making the buzzer a task would work I can imagine.

I currently have a class which wants to enable the buzzer every 5 / 30 seconds (depending on room temperature) to alert for X seconds, the enabling works by sending the event containing X following the observer pattern.

I'll have a look at example 21 and see if that can help clarity.

Thanks for your input, I really appreciate the thoughts

Kind regards,

Lerring

arkhipenko commented 4 years ago

No worries. You could also send your full sketch to arkhipenko@hotmail.com - I can look over and make suggestions.

Just to make sure - this is a cooperative multitasking library, not pre-emptive. You have to use TS for all your tasks, not just the buzzer. (Asking because you were using private scheduler as a member inside the task - that not the best way and won't work in many cases as scheduler does not have control outside of its task chain).

dratsuc1 commented 4 years ago

I've sent over an email.

TS is the only task scheduler I have used, One acting as a heart beat of the task execution and the second in this example.

arkhipenko commented 4 years ago

Closing this thread as it moved to PM space.