Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example using delay or yield in class instantiated in task #17

Open
thijse opened this issue May 22, 2020 · 7 comments
Open

Example using delay or yield in class instantiated in task #17

thijse opened this issue May 22, 2020 · 7 comments

Comments

@thijse
Copy link

thijse commented May 22, 2020

It would be great if you can add an example on how to use a non blocking delay in a other class than the Task itself.

I am now doing it like the example below (based on the Simple.ino example), but it requires changing the scheduler to make delay & yield public

class PrintManager  {
  protected:
    Task* _task;
  public:
    PrintManager(Task* task) {
      _task = task;
    }
    
    void print() {
        Serial.println("Print Loop Start");
        _task->delay(4000);
        Serial.println("Print Loop End");
        _task->delay(4000);
    }
};


class PrintTask : public Task {
public:
    PrintTask() : Task(), printManager((Task *) this){}; 

protected:
    PrintManager printManager;
    void loop()  {      
        printManager.print();
    }
} print_task;

Thanks!

@nrwiersma
Copy link
Owner

Hi,

This is not something I have ever thought of doing. Off the top of my head, I would probably pass the delay function through as a param, rather than the task, would this work for you?

@thijse
Copy link
Author

thijse commented May 23, 2020

Hi,
I am currently using with a modified version of NTPclient to do a non-blocking wait for an update from a NTP server, but I expect there are many more libraries that have internal delays that I may want to make non-blocking in the future

What would passing the function look like? It should still set delay_time and delay_ms of the task in order to have shouldRun run correctly, right?

ps. By the way, thanks for the library!

@nrwiersma
Copy link
Owner

Hi,

It would look something like this:

typedef void (*delayFunc)(unsigned long ms);

class PrintManager  {
  protected:
    delayFunc _delay;
  public:
    PrintManager(delayFunc delay) {
      _delay = delay;
    }
    
    void print() {
        Serial.println("Print Loop Start");
        _delay(4000);
        Serial.println("Print Loop End");
        _delay(4000);
    }
};


class PrintTask : public Task {
public:
    PrintTask() : Task(), printManager(this->delay){}; 

protected:
    PrintManager printManager;
    void loop()  {      
        printManager.print();
    }
} print_task;

I havnt tried the code, but it is around there somewhere.

@thijse
Copy link
Author

thijse commented May 23, 2020

Thanks, I will try it out!

@thijse
Copy link
Author

thijse commented Jun 7, 2020

I tried another approach which would not require passing a function or object:

I added the static function

void SchedulerClass::delay(unsigned long ms) {
	 current->delay(ms);
 }

to Scheduler. My thinking was that I could then call it the Non-Task object (e.g. PrintManager) as
Scheduler.Delay(4000)
or
SchedulerClass::Delay(4000)
Which would then call the Delay function in the Task that is currently running

However, this gives a niece big crash as soon as current->delay calls the underlying cont_yield(&context); in Task class.

Do you have any idea why? I am afraid that I do not understand the mechanics deeply enough to see why this fails.

@nrwiersma
Copy link
Owner

It entirely depends on how this is done. It would be very difficult to say without being able to map its exact flow.

@dbuezas
Copy link
Contributor

dbuezas commented Feb 1, 2021

I'd also like to call delay and yield without passing those functions all the way down. I just tried what @thijse proposes and it seems to work just fine.

However, this gives a niece big crash as soon as current->delay calls the underlying cont_yield(&context); in Task class.

did you also happen to define yield as a class method?, if you did, make sure to also change yield(); to ::yield(); inside void SchedulerClass::begin() {}. Otherwise that yield refers to the class method, and then it crashes. See Qualified name lookup

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants