AceRoutine  1.2.1
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
Public Member Functions | Protected Types | Protected Member Functions | Static Protected Attributes | Friends | List of all members
ace_routine::Coroutine Class Referenceabstract

Base class of all coroutines. More...

#include <Coroutine.h>

Public Member Functions

const ace_common::FCString & getName () const
 Human-readable name of the coroutine.
 
virtual int runCoroutine ()=0
 The body of the coroutine. More...
 
virtual unsigned long coroutineMillis () const
 Returns the current millisecond clock. More...
 
virtual unsigned long coroutineMicros () const
 Returns the current millisecond clock. More...
 
virtual unsigned long coroutineSeconds () const
 Returns the current clock in unit of seconds, truncated to the lower 16-bits. More...
 
void suspend ()
 Suspend the coroutine at the next scheduler iteration. More...
 
void resume ()
 Add a Suspended coroutine into the head of the scheduler linked list, and change the state to Yielding. More...
 
void reset ()
 Reset the coroutine to its initial state. More...
 
bool isDelayExpired () const
 Check if delay time is over.
 
bool isSuspended () const
 The coroutine was suspended with a call to suspend().
 
bool isYielding () const
 The coroutine returned using COROUTINE_YIELD().
 
bool isDelaying () const
 The coroutine returned using COROUTINE_DELAY().
 
bool isRunning () const
 The coroutine is currently running. More...
 
bool isEnding () const
 The coroutine returned using COROUTINE_END(). More...
 
bool isTerminated () const
 The coroutine was terminated by the scheduler with a call to setTerminated(). More...
 
bool isDone () const
 The coroutine is either Ending or Terminated. More...
 
void setupCoroutine (const char *name)
 Initialize the coroutine for the CoroutineScheduler, set it to Yielding state, and add it to the linked list of coroutines. More...
 
void setupCoroutine (const __FlashStringHelper *name)
 Same as setupCoroutine(const char*) except using flash string type. More...
 
void setupCoroutineOrderedByName (const char *name)
 A version of setupCoroutine(const char*) where the ordering of the coroutines executed by CoroutineScheduler is ordered by the name. More...
 
void setupCoroutineOrderedByName (const __FlashStringHelper *name)
 A version of setupCoroutine(const __FlashStringHelper*) where the ordering of the coroutines executed by CoroutineScheduler is ordered by the name. More...
 

Protected Types

typedef uint8_t Status
 The execution status of the coroutine, corresponding to the COROUTINE_YIELD(), COROUTINE_DELAY(), COROUTINE_AWAIT() and COROUTINE_END() macros. More...
 

Protected Member Functions

 Coroutine ()
 Constructor. More...
 
virtual ~Coroutine ()
 Destructor.
 
Status getStatus () const
 Return the status of the coroutine. More...
 
void statusPrintTo (Print &printer)
 Print the human-readable string of the Status.
 
void setJump (void *jumpPoint)
 Pointer to label where execute will start on the next call to runCoroutine().
 
void * getJump () const
 Pointer to label where execute will start on the next call to runCoroutine().
 
void setRunning ()
 Set the kStatusRunning state.
 
void setYielding ()
 Set the kStatusDelaying state.
 
void setDelaying ()
 Set the kStatusDelaying state.
 
void setEnding ()
 Set the kStatusEnding state.
 
void setTerminated ()
 Set status to indicate that the Coroutine has been removed from the Scheduler queue. More...
 
void setDelayMillis (uint16_t delayMillis)
 Configure the delay timer for delayMillis. More...
 
void setDelayMicros (uint16_t delayMicros)
 Configure the delay timer for delayMicros. More...
 
void setDelaySeconds (uint16_t delaySeconds)
 Configure the delay timer for delaySeconds. More...
 

Static Protected Attributes

static const Status kStatusSuspended = 0
 Coroutine has been suspended using suspend() and the scheduler should remove it from the queue upon the next iteration. More...
 
static const Status kStatusYielding = 1
 Coroutine returned using the COROUTINE_YIELD() statement.
 
static const Status kStatusDelaying = 2
 Coroutine returned using the COROUTINE_DELAY() statement.
 
static const Status kStatusRunning = 3
 Coroutine is currenly running. More...
 
static const Status kStatusEnding = 4
 Coroutine executed the COROUTINE_END() statement.
 
static const Status kStatusTerminated = 5
 Coroutine has ended and no longer in the scheduler queue.
 
static const uint8_t kDelayTypeMillis = 0
 Delay using units of millis.
 
static const uint8_t kDelayTypeMicros = 1
 Delay using units of micros.
 
static const uint8_t kDelayTypeSeconds = 2
 Delay using units of seconds.
 

Friends

class CoroutineScheduler
 
class ::AceRoutineTest_statusStrings
 
class ::SuspendTest_suspendAndResume
 

Detailed Description

Base class of all coroutines.

The actual coroutine code is an implementation of the virtual runCoroutine() method.

Definition at line 265 of file Coroutine.h.

Member Typedef Documentation

◆ Status

typedef uint8_t ace_routine::Coroutine::Status
protected

The execution status of the coroutine, corresponding to the COROUTINE_YIELD(), COROUTINE_DELAY(), COROUTINE_AWAIT() and COROUTINE_END() macros.

The finite state diagram looks like this:

*          Suspended
*          ^       ^
*         /         \
*        /           \
*       v             \
* Yielding          Delaying
*      ^               ^
*       \             /
*        \           /
*         \         /
*          v       v
*           Running
*              |
*              |
*              v
*           Ending
*              |
*              |
*              v
*         Terminated
* 

Definition at line 471 of file Coroutine.h.

Constructor & Destructor Documentation

◆ Coroutine()

ace_routine::Coroutine::Coroutine ( )
inlineprotected

Constructor.

All subclasses are expected to call either setupCoroutine(const char*) or setupCoroutine(const __FlashStringHelper*) before the CoroutineScheduler is used. The COROUTINE() macro will automatically call setupCoroutine().

See comment in setupCoroutine(const __FlashStringHelper*) for reason why the setupCoroutine() function is used instead of chaining the name through the constructor.

Definition at line 515 of file Coroutine.h.

Member Function Documentation

◆ coroutineMicros()

unsigned long ace_routine::Coroutine::coroutineMicros ( ) const
virtual

Returns the current millisecond clock.

By default it returns the global micros() function from Arduino but can be overridden for testing.

Definition at line 118 of file Coroutine.cpp.

◆ coroutineMillis()

unsigned long ace_routine::Coroutine::coroutineMillis ( ) const
virtual

Returns the current millisecond clock.

By default it returns the global millis() function from Arduino but can be overridden for testing.

Definition at line 114 of file Coroutine.cpp.

◆ coroutineSeconds()

unsigned long ace_routine::Coroutine::coroutineSeconds ( ) const
virtual

Returns the current clock in unit of seconds, truncated to the lower 16-bits.

This is an approximation of (millis / 1000). It does not need to be perfectly accurate because COROUTINE_DELAY_SECONS() is not guaranteed to be precise.

Definition at line 122 of file Coroutine.cpp.

◆ getStatus()

Status ace_routine::Coroutine::getStatus ( ) const
inlineprotected

Return the status of the coroutine.

Used by the CoroutineScheduler.

Definition at line 521 of file Coroutine.h.

◆ isDone()

bool ace_routine::Coroutine::isDone ( ) const
inline

The coroutine is either Ending or Terminated.

This method is recommended over isEnding() or isTerminated() because it works when the coroutine is executed either manually or through the CoroutineScheduler.

Definition at line 382 of file Coroutine.h.

◆ isEnding()

bool ace_routine::Coroutine::isEnding ( ) const
inline

The coroutine returned using COROUTINE_END().

In most cases, isDone() is recommended instead because it works when coroutines are executed manually or through the CoroutineScheduler.

Definition at line 367 of file Coroutine.h.

◆ isRunning()

bool ace_routine::Coroutine::isRunning ( ) const
inline

The coroutine is currently running.

True only within the coroutine.

Definition at line 360 of file Coroutine.h.

◆ isTerminated()

bool ace_routine::Coroutine::isTerminated ( ) const
inline

The coroutine was terminated by the scheduler with a call to setTerminated().

In most cases, isDone() should be used instead because it works when coroutines are executed manually or through the CoroutineScheudler.

Definition at line 375 of file Coroutine.h.

◆ reset()

void ace_routine::Coroutine::reset ( )
inline

Reset the coroutine to its initial state.

Only the Coroutine base-class state is reset to the original state. If the subclass runCoroutine() uses any static variables (for example, a loop counter), you must reset those variables manually as well, since this library does not have any knowledge about them.

It is expected that this method will be called from outside the runCoroutine() method. If it is called within the method, I'm not sure what will happen. I think the coroutine will abandon the current continuation point, and start executing from the beginning of the Coroutine upon the next iteration.

Definition at line 342 of file Coroutine.h.

◆ resume()

void ace_routine::Coroutine::resume ( )

Add a Suspended coroutine into the head of the scheduler linked list, and change the state to Yielding.

If the coroutine is in any other state, this method does nothing. This method works only if the CoroutineScheduler::loop() is used.

Definition at line 103 of file Coroutine.cpp.

◆ runCoroutine()

virtual int ace_routine::Coroutine::runCoroutine ( )
pure virtual

The body of the coroutine.

The COROUTINE macro creates a subclass of this class and puts the body of the coroutine into this method.

Returns
The return value is always ignored. This method is declared to return an int to prevent the user from accidentally returning from this method using an explicit 'return' statement instead of through one of the macros (e.g. COROUTINE_YIELD(), COROUTINE_DELAY(), COROUTINE_AWAIT() or COROUTINE_END()).

◆ setDelayMicros()

void ace_routine::Coroutine::setDelayMicros ( uint16_t  delayMicros)
inlineprotected

Configure the delay timer for delayMicros.

Similar to seDelayMillis(), the maximum delay is 32767 micros.

Definition at line 583 of file Coroutine.h.

◆ setDelayMillis()

void ace_routine::Coroutine::setDelayMillis ( uint16_t  delayMillis)
inlineprotected

Configure the delay timer for delayMillis.

The maximum duration is set to (UINT16_MAX / 2) (i.e. 32767 milliseconds) if given a larger value. This makes the longest allowable time between two successive calls to isDelayExpired() for a given coroutine to be 32767 (UINT16_MAX - UINT16_MAX / 2 - 1) milliseconds, which should be long enough for all practical use-cases. (The '- 1' comes from an edge case where isDelayExpired() evaluates to be true in the CoroutineScheduler::runCoroutine() but becomes to be false in the COROUTINE_DELAY() macro inside Coroutine::runCoroutine()) because the clock increments by 1 millisecond.)

Definition at line 571 of file Coroutine.h.

◆ setDelaySeconds()

void ace_routine::Coroutine::setDelaySeconds ( uint16_t  delaySeconds)
inlineprotected

Configure the delay timer for delaySeconds.

Similar to seDelayMillis(), the maximum delay is 32767 seconds.

Definition at line 595 of file Coroutine.h.

◆ setTerminated()

void ace_routine::Coroutine::setTerminated ( )
inlineprotected

Set status to indicate that the Coroutine has been removed from the Scheduler queue.

Should be used only by the CoroutineScheduler.

Definition at line 556 of file Coroutine.h.

◆ setupCoroutine() [1/2]

void ace_routine::Coroutine::setupCoroutine ( const __FlashStringHelper *  name)

Same as setupCoroutine(const char*) except using flash string type.

Normally, the name would be passed from the subclass into this parent class through constructor chaining. But if we try to do that with the F() string, the compiler complains because F() macros work only inside a function. Therefore, the COROUTINE() macro uses the setupCoroutine() method to pass the name of the coroutine.

The problem doesn't exist for a (const char*) but for consistency, I made both types of strings pass through the setupCoroutine() method instead of chaining the constructor.

Parameters
nameThe name of the coroutine as a human-readable string.

Definition at line 59 of file Coroutine.cpp.

◆ setupCoroutine() [2/2]

void ace_routine::Coroutine::setupCoroutine ( const char *  name)

Initialize the coroutine for the CoroutineScheduler, set it to Yielding state, and add it to the linked list of coroutines.

This method is called automatically by the COROUTINE() macro. It needs to be called manually when using coroutines which were manually created without using that COROUTINE() macro.

This method could have been named init() or setup() but since this class expected to be used as a mix-in class to create more complex classes which could have its own setup() methods, the longer name seemed more clear.

Parameters
nameThe name of the coroutine as a human-readable string.

Definition at line 53 of file Coroutine.cpp.

◆ setupCoroutineOrderedByName() [1/2]

void ace_routine::Coroutine::setupCoroutineOrderedByName ( const __FlashStringHelper *  name)

A version of setupCoroutine(const __FlashStringHelper*) where the ordering of the coroutines executed by CoroutineScheduler is ordered by the name.

This was the default behavior of setupCoroutine() before v1.2. This method recreates the previous behavior, but it exists only for testing purposes where a deterministic ordering is required. The stability of this method is not guaranteed and client code should not use this method.

Definition at line 71 of file Coroutine.cpp.

◆ setupCoroutineOrderedByName() [2/2]

void ace_routine::Coroutine::setupCoroutineOrderedByName ( const char *  name)

A version of setupCoroutine(const char*) where the ordering of the coroutines executed by CoroutineScheduler is ordered by the name.

This was the default behavior of setupCoroutine() before v1.2. This method recreates the previous behavior, but it exists only for testing purposes where a deterministic ordering is required. The stability of this method is not guaranteed and client code should not use this method.

Definition at line 65 of file Coroutine.cpp.

◆ suspend()

void ace_routine::Coroutine::suspend ( )
inline

Suspend the coroutine at the next scheduler iteration.

If the coroutine is already in the process of ending or is already terminated, then this method does nothing. A coroutine cannot use this method to suspend itself, it can only suspend some other coroutine. Currently, there is no ability for a coroutine to suspend itself, that would require the addition of a COROUTINE_SUSPEND() macro. Also, this method works only if the CoroutineScheduler::loop() is used because the suspend functionality is implemented by the CoroutineScheduler.

Definition at line 316 of file Coroutine.h.

Member Data Documentation

◆ kStatusRunning

const Status ace_routine::Coroutine::kStatusRunning = 3
staticprotected

Coroutine is currenly running.

True only within the coroutine itself.

Definition at line 488 of file Coroutine.h.

◆ kStatusSuspended

const Status ace_routine::Coroutine::kStatusSuspended = 0
staticprotected

Coroutine has been suspended using suspend() and the scheduler should remove it from the queue upon the next iteration.

We don't distinguish whether the coroutine is still in the queue or not with this status. We can add that later if we need to.

Definition at line 479 of file Coroutine.h.


The documentation for this class was generated from the following files: