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

PolledTimeout Class for wrapping millis() loops (WIP) #5198

Merged
merged 16 commits into from
Nov 26, 2018
Merged

PolledTimeout Class for wrapping millis() loops (WIP) #5198

merged 16 commits into from
Nov 26, 2018

Conversation

devyte
Copy link
Collaborator

@devyte devyte commented Oct 2, 2018

Class to wrap typical polled timing constructs:

  1. wait n ms before continuing (oneshot)
  2. retry some test until n ms timeout has expired {oneshot)
  3. execute some code body once every n ms (periodic)

Classes are declared inside namespace esp8266. Use model is meant for stack declaration (declaration initializes, i.e.: RAII) with one exception: do something in the loop every n ms. In that last case, declaration must be global and the global must be reset() at the end of setup().

I expect to add a device test as soon as I figure out htf they work.

Usage is something like this:

void test1()
{
  using namespace esp8266;
  polledTimeoutOneShot timeout(3000);

  Serial.println("OneShot Timeout 3000ms");

  Serial.print("before 1\n");
  while(!timeout.expired())
    yield();
  Serial.print("after 1\n");

  Serial.print("reset\n");
  timeout.reset();

  Serial.print("before 2\n");  
  while(!timeout)
    yield();
  Serial.print("after 2\n");
}

void test2()
{
  using namespace esp8266;
  polledTimeoutPeriodic timeout(3000);

  Serial.println("Periodic Timeout 1T 3000ms");

  Serial.print("before 1\n");
  while(!timeout)
    yield();

  Serial.print("no reset needed\n");

  Serial.print("before 2\n");  
  while(!timeout)
    yield();
  Serial.print("after 2\n");
}

void test3()
{
  using namespace esp8266;
  polledTimeoutPeriodic timeout(1000); 

  Serial.println("Periodic 10T Timeout 1000ms");

  int counter = 10;
  while(1)
  {
    if(timeout)
    {
      Serial.print("*");
      if(!--counter)
        break;
      yield();
    }
  }
}

cores/esp8266/PolledTimeout.h Outdated Show resolved Hide resolved
@d-a-v
Copy link
Collaborator

d-a-v commented Oct 2, 2018

Does it make sense to add such extenders for ease of use,
or should this be left to the user as an exercise in personal sketches ?

class EspTimeoutMs: public esp8266::polledTimeoutOneShot
{
public:

    EspTimeoutMs(timeType timeout = 0): polledTimeoutOneShot(timeout)
    {
    }

    EspTimeoutMs& operator= (timeType timeout)
    {
        _timeout = timeout;
        return *this;
    }

    bool expired()
    {
        yield();
        return expiredOneShot();
    }
    
    operator bool()
    {
        return expired(); 
    }
};

class EspEveryMs: public esp8266::polledTimeoutPeriodic
{
public:

    EspEveryMs(timeType timeout = 0): polledTimeoutEvery(timeout)
    {
    }

    EspEveryMs& operator= (timeType timeout)
    {
        _timeout = timeout;
        return *this;
    }

    operator bool()
    {
        bool ret = expired(); 
        if (ret)
            reset();
        return ret;
    }
};
// yield not needed, semantically it's in the name ("Esp"Timeout)
void test()
{
  for (EspTimeoutMs timeout = 3000; !timeout; )
    doStuff();
}
EspEveryMs changeLedNow = 1000;

void test()
{
  if (changeLedNow)
    digitalWrite(LED_PIN, 1 - digitalRead(LED_PIN));
}

I would call this the glue between perfect c++ and the arduino world which is primarily aimed at beginners.

edit: we could even do this (with trivial iterator emulation like there)

// yield not needed, semantically it's in the name ("Esp"Timeout)
void test()
{
  for (auto timeout: EspTimeoutMs(3000))
    doStuff();
}

@yoursunny
Copy link
Contributor

The API looks good.
I wonder why type names are starting with a lower case letter? It’s different from most other code that uses an upper case letter.

@devyte devyte mentioned this pull request Nov 21, 2018
@devyte
Copy link
Collaborator Author

devyte commented Nov 23, 2018

@d-a-v I've been thinking about your iterator emulation. My original thought was that it doesn't make sense, because iterators are meant for going over a range of items in a container.
However, it can in fact make sense when you want to have e.g.: soStuff() aware of how time passes while waiting for the timeout to expire. In your example, it could be something like:

void test()
{
  for (auto currtime: EspTimeoutMs(3000))
    doStuff(currtime);
}

A use case for doStuff() could be sampling something, like the ADC, so the above would sample the ADC for a specific amount of time. There are other cases where you want to do something in a time-aware manner while waiting for a timeout to expire.

@devyte
Copy link
Collaborator Author

devyte commented Nov 26, 2018

Merging this as-is given that it's needed in many places.
Possible future work: iterator-like syntax

@devyte devyte merged commit a501d3c into esp8266:master Nov 26, 2018
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

Successfully merging this pull request may close these issues.

4 participants