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

restarting a Coroutine after it has finished #18

Closed
BiffBish opened this issue Nov 2, 2020 · 9 comments
Closed

restarting a Coroutine after it has finished #18

BiffBish opened this issue Nov 2, 2020 · 9 comments

Comments

@BiffBish
Copy link

BiffBish commented Nov 2, 2020

So im using AceRoutine for an arduino project and theres some things that im confused about. ill try to explain what im trying to do but if you dont understand please let me know. Lets say i have an Alarm Coroutine. that coroutine flashes a light on and off 10 times.

COROUTINE(Alarm){
COROUTINE_BEGIN();
static int Alarmi1 = 0;
for (Alarmi1 = 0; Alarmi1 < 10; Alarmi1++)
{
digitalWrite(A3, 1);
COROUTINE_DELAY(50);
digitalWrite(A3, 0);
COROUTINE_DELAY(50);
}
COROUTINE_END();
}

So what i want is a way for me to be able to call Alarm.RunOnce(). and it runs the coroutine Once and flashes the light 10 times.
the problem is that it just Turns the light on and stops when i try Alarm.runCorutine(). now i believe the function runCoroutine is what is constantly checking if it should start back up and resume exicution so you need to have that function in the loop. but the problem is when i do that it blinks 10 times and it stops. and whenever i call runCoroutine again nothing happens. it just gets locked down. any help would be apprecheated if you have discord and would like to talk there my discord is BiffBish#9043

@BiffBish
Copy link
Author

BiffBish commented Nov 2, 2020

If you've ever used unity I would like to be able to use the coroutines like unity uses them

@bxparks
Copy link
Owner

bxparks commented Nov 2, 2020

Hello,
Let's see if I understand your question.

The COROUTINE_DELAY(50) macro contains an internal "yield()" function. Each time Alarm.runCoroutine() is called, the coroutine effectively resumes execution just after the "yield()". After the Alarm blinks 10 times, the coroutine reaches its isDone() state, and all further calls to runCoroutine() does nothing.

If you want to restart the coroutine to blink 10 times again, you can use the Coroutine::reset() function that I added just recently in v1.1. Luckily for you, the reset() method will cause your Alarm1 static variable to reset to 0 (because it causes the runCoroutine() to start from the top beginning of the method, causing the for loop to re-init the Alarm1 variable to 0.) In more complicated Coroutines, you may need to use a Manual Coroutine (https://github.com/bxparks/AceRoutine#manual-coroutines-recommended) and provide your own myReset() method that resets your internal state manually (and then calls Coroutine::reset()).

If you upgrade to v1.1, note that it now has a dependency to my AceCommon (https://github.com/bxparks/AceCommon) library which you can install through the Arduino Library Manager. I noted this in the CHANGELOG.md, but I notice that I didn't make that clear in the README.md. I'll update that shortly.

Does this help?

(Sorry, I don't have a discord account..)

@bxparks bxparks changed the title Hey I'm trying to use this and I'm confused what im doing wrong. restarting a Coroutine after it has finished Nov 2, 2020
@BiffBish
Copy link
Author

BiffBish commented Nov 2, 2020

First off. Thanks for the lighting quick reply. Secondly I'll try your solution in a bit. Currently I just have a parallel booliean called AlarmR that gets true in the very beginning of the coroutine and gets false at the end of the corutine. And in the main loop there is
if(alarmM) alarm.runcoroutine();

And it's working for now. But if I run into further problems I'll switch to the coroutine manager. Because currently I'm not using the coroutine manager. Also I'm converting the coroutines to loop coroutines and removing the coroutine_end

@bxparks
Copy link
Owner

bxparks commented Nov 2, 2020 via email

@BiffBish
Copy link
Author

BiffBish commented Nov 2, 2020

bool AlarmR = false;
COROUTINE(Alarm){
  COROUTINE_LOOP() {
    AlarmR = true;
    static int AlarmI1 = 0;
    for (AlarmI1 = 0; AlarmI1 < 10; AlarmI1++)
    {
      digitalWrite(A5, 1);
      digitalWrite(A4, 1);
      COROUTINE_DELAY(50);
      digitalWrite(A4, 0);
      COROUTINE_DELAY(50);
    }
    AlarmR = false;
    COROUTINE_YIELD();
  }
}

void Loop(){
  if(AlarmR){
    Alarm.runCoroutine();
  }
}
void StartAlarm(){
  Alarm.runCoroutine();
}

@BiffBish
Copy link
Author

BiffBish commented Nov 2, 2020

and there's not going to be one or two loops there going to be like 10 or so. and i need to have one of the if statements for each coroutine

@bxparks
Copy link
Owner

bxparks commented Nov 2, 2020

That code looks great. In fact, that was the only way to do what you want to do prior to my adding the Coroutine::reset() method.

Here's a slightly different way to accomplish the same thing, which you might find cleaner (the indentation is probably off, hard to get that right using this web edit box):

#include <AceRoutine.h>

class Alarm: public ace_routine::Coroutine {
public:
  Alarm() {}

  int runCoroutine() override {
    COROUTINE_LOOP() {
      if (enable) {
         for (counter = 0; counter < 10; counter++) {
           digitalWrite(A5, 1);
           digitalWrite(A4, 1);
           COROUTINE_DELAY(50);
           digitalWrite(A4, 0);
           COROUTINE_DELAY(50);
         } // for
         enable = false;
       } // if
       COROUTINE_YIELD();
      } // COROUTINE_LOOP()
    }

  void setEnable(bool state) { enable = state; }

private:
  bool enable = false;
  int counter;
};

// Create instance of the Alarm coroutine
Alarm alarm;

void loop(){
  alarm.runCoroutine();
}

void StartAlarm(){
  alarm.setEnable(true);
}

The nice thing about defining your custom Alarm class is that you can create multiple instances of it, with slightly different variations if you want. The internal counter and enable variables of each alarm don't interfere with each other.

@bxparks
Copy link
Owner

bxparks commented Nov 8, 2020

Can I close this? I don't think there is anything for me to do. The only additional comment I can make is that if you use the latest version of AceRoutine, you can use Coroutine::reset() in the StartAlarm() function, and remove all the code around the Alarm::enable flag. The code becomes simpler.

@BiffBish
Copy link
Author

BiffBish commented Nov 8, 2020

Sure I'm fine with closing it. Everything makes sense.

@bxparks bxparks closed this as completed Nov 8, 2020
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

2 participants