AceRoutine
1.5.0
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
|
#include <stdint.h>
#include <Print.h>
#include <AceCommon.h>
#include "CoroutineProfiler.h"
#include "ClockInterface.h"
#include "compat.h"
Go to the source code of this file.
Classes | |
class | ace_routine::CoroutineSchedulerTemplate< T_COROUTINE > |
Class that manages instances of the Coroutine class, and executes them in a round-robin fashion. More... | |
class | ace_routine::CoroutineTemplate< T_CLOCK, T_DELAY > |
Base class of all coroutines. More... | |
Macros | |
#define | ACE_ROUTINE_DEPRECATED |
Macro that indicates a deprecation. | |
#define | COROUTINE(...) GET_COROUTINE(__VA_ARGS__, COROUTINE2, COROUTINE1)(__VA_ARGS__) |
Create a Coroutine instance named 'name'. More... | |
#define | GET_COROUTINE(_1, _2, NAME, ...) NAME |
Internal helper macro to allow overloading of the COROUTINE() macro. | |
#define | COROUTINE1(name) |
Implement the 1-argument COROUTINE() macro. More... | |
#define | COROUTINE2(className, name) |
Implement the 2-argument COROUTINE() macro. More... | |
#define | EXTERN_COROUTINE(...) |
Create an extern reference to a coroutine that is defined in another .cpp file. More... | |
#define | GET_EXTERN_COROUTINE(_1, _2, NAME, ...) NAME |
Internal helper macro to allow overloading of the EXTERN_COROUTINE() macro. | |
#define | EXTERN_COROUTINE1(name) |
Implement the 1-argument EXTERN_COROUTINE() macro. More... | |
#define | EXTERN_COROUTINE2(className, name) |
Implement the 2-argument EXTERN_COROUTINE() macro. More... | |
#define | COROUTINE_BEGIN() |
Mark the beginning of a coroutine. More... | |
#define | COROUTINE_LOOP() |
Mark the beginning of a coroutine loop. More... | |
#define | COROUTINE_YIELD_INTERNAL() |
Implement the common logic for COROUTINE_YIELD(), COROUTINE_AWAIT(), COROUTINE_DELAY(). More... | |
#define | COROUTINE_YIELD() |
Yield execution to another coroutine. More... | |
#define | COROUTINE_AWAIT(condition) |
Yield until condition is true, then execution continues. More... | |
#define | COROUTINE_DELAY(delayMillis) |
Yield for delayMillis. More... | |
#define | COROUTINE_DELAY_MICROS(delayMicros) |
Yield for delayMicros. More... | |
#define | COROUTINE_DELAY_SECONDS(delaySeconds) |
Yield for delaySeconds. More... | |
#define | COROUTINE_END() |
Mark the end of a coroutine. More... | |
Typedefs | |
using | ace_routine::Coroutine = CoroutineTemplate< ClockInterface, uint16_t > |
A concrete template instance of CoroutineTemplate that uses ClockInterface which uses the built-in millis() or micros() function. More... | |
All coroutines are instances of the Coroutine base class. The COROUTINE() macro creates these instances, and registers them to automatically run when CoroutineScheduler::loop() is called.
Various macros use macro overloading to implement a 1-argument and a 2-argument version. See https://stackoverflow.com/questions/11761703 to description of how that works.
The computed goto is a GCC extension: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html The noinline and noclone attributes make sure that label pointers are always the same. I'm not 100% sure they are needed here, but they don't seem to hurt.
Definition in file Coroutine.h.
#define COROUTINE | ( | ... | ) | GET_COROUTINE(__VA_ARGS__, COROUTINE2, COROUTINE1)(__VA_ARGS__) |
Create a Coroutine instance named 'name'.
Two forms are supported
The 1-argument form uses the Coroutine class as the base class of the coroutine. The 2-argument form uses the user-provided className which must be a subclass of Coroutine.
The code in {} following this macro becomes the body of the Coroutine::runCoroutine() method.
Definition at line 81 of file Coroutine.h.
#define COROUTINE1 | ( | name | ) |
Implement the 1-argument COROUTINE() macro.
Definition at line 88 of file Coroutine.h.
#define COROUTINE2 | ( | className, | |
name | |||
) |
Implement the 2-argument COROUTINE() macro.
Definition at line 98 of file Coroutine.h.
#define COROUTINE_AWAIT | ( | condition | ) |
Yield until condition is true, then execution continues.
This is functionally equivalent to:
but potentially slightly more efficient.
Definition at line 185 of file Coroutine.h.
#define COROUTINE_BEGIN | ( | ) |
Mark the beginning of a coroutine.
Definition at line 141 of file Coroutine.h.
#define COROUTINE_DELAY | ( | delayMillis | ) |
Yield for delayMillis.
A delayMillis of 0 is functionally equivalent to COROUTINE_YIELD(). To save memory, the delayMillis is stored as a uint16_t but the actual maximum is limited to 32767 millliseconds. See setDelayMillis() for the reason for this limitation.
If you need to wait for longer than that, use a for-loop to call COROUTINE_DELAY() as many times as necessary.
This could have been implemented using COROUTINE_AWAIT() but this macro matches the global delay(millis) function already provided by the Arduino API. Also having a separate kStatusDelaying state allows the CoroutineScheduler to be slightly more efficient by avoiding the call to Coroutine::runCoroutine() if the delay has not expired.
Definition at line 209 of file Coroutine.h.
#define COROUTINE_DELAY_MICROS | ( | delayMicros | ) |
Yield for delayMicros.
Similiar to COROUTINE_DELAY(delayMillis).
Definition at line 220 of file Coroutine.h.
#define COROUTINE_DELAY_SECONDS | ( | delaySeconds | ) |
Yield for delaySeconds.
Similar to COROUTINE_DELAY(delayMillis).
The accuracy of the delay interval in units of seconds is not perfectly accurate. The current implementation uses the builtin millis() to infer the "seconds". The millis() function returns a value that overflows after 4,294,967.296 seconds. Therefore, the last inferred second just before overflowing contains only 0.296 seconds instead of a full second. A delay which straddles this overflow will return 0.704 seconds earlier than it should.
On microcontrollers without hardware integer division instruction, (i.e. AVR, SAMD21, ESP8266), the division by 1000 is relatively slow and consumes significant amount of flash memory (100-150 bytes on AVR).
Definition at line 245 of file Coroutine.h.
#define COROUTINE_END | ( | ) |
Mark the end of a coroutine.
Subsequent calls to Coroutine::runCoroutine() will do nothing.
Definition at line 259 of file Coroutine.h.
#define COROUTINE_LOOP | ( | ) |
Mark the beginning of a coroutine loop.
Can be used instead of COROUTINE_BEGIN() at the beginning of a Coroutine.
Definition at line 151 of file Coroutine.h.
#define COROUTINE_YIELD | ( | ) |
Yield execution to another coroutine.
Definition at line 168 of file Coroutine.h.
#define COROUTINE_YIELD_INTERNAL | ( | ) |
Implement the common logic for COROUTINE_YIELD(), COROUTINE_AWAIT(), COROUTINE_DELAY().
Definition at line 159 of file Coroutine.h.
#define EXTERN_COROUTINE | ( | ... | ) |
Create an extern reference to a coroutine that is defined in another .cpp file.
The extern reference is needed before it can be used. Two forms are supported:
Definition at line 115 of file Coroutine.h.
#define EXTERN_COROUTINE1 | ( | name | ) |
Implement the 1-argument EXTERN_COROUTINE() macro.
Definition at line 125 of file Coroutine.h.
#define EXTERN_COROUTINE2 | ( | className, | |
name | |||
) |
Implement the 2-argument EXTERN_COROUTINE() macro.
Definition at line 133 of file Coroutine.h.
using ace_routine::Coroutine = typedef CoroutineTemplate<ClockInterface, uint16_t> |
A concrete template instance of CoroutineTemplate that uses ClockInterface which uses the built-in millis() or micros() function.
This becomes the base class of all user-defined coroutines created using the COROUTINE() macro or through manual subclassing of this class.
Definition at line 825 of file Coroutine.h.