AceRoutine
1.5.0
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
|
Go to the documentation of this file.
25 #ifndef ACE_ROUTINE_COROUTINE_H
26 #define ACE_ROUTINE_COROUTINE_H
30 #include <AceCommon.h>
31 #include "CoroutineProfiler.h"
32 #include "ClockInterface.h"
35 class __FlashStringHelper;
36 class AceRoutineTest_statusStrings;
37 class SuspendTest_suspendAndResume;
59 #if defined(__GNUC__) || defined(__clang__)
60 #define ACE_ROUTINE_DEPRECATED __attribute__((deprecated))
61 #elif defined(_MSC_VER)
62 #define ACE_ROUTINE_DEPRECATED __declspec(deprecated)
64 #pragma message("WARNING: Implement ACE_ROUTINE_DEPRECATED for this compiler")
65 #define ACE_ROUTINE_DEPRECATED
81 #define COROUTINE(...) \
82 GET_COROUTINE(__VA_ARGS__, COROUTINE2, COROUTINE1)(__VA_ARGS__)
85 #define GET_COROUTINE(_1, _2, NAME, ...) NAME
88 #define COROUTINE1(name) \
89 struct Coroutine_##name : ace_routine::Coroutine { \
91 int runCoroutine() override; \
93 Coroutine_##name :: Coroutine_##name() { \
95 int Coroutine_##name :: runCoroutine()
98 #define COROUTINE2(className, name) \
99 struct className##_##name : className { \
100 className##_##name(); \
101 int runCoroutine() override; \
103 className##_##name :: className##_##name() { \
105 int className##_##name :: runCoroutine()
115 #define EXTERN_COROUTINE(...) \
116 GET_EXTERN_COROUTINE(\
117 __VA_ARGS__, EXTERN_COROUTINE2, EXTERN_COROUTINE1)(__VA_ARGS__)
122 #define GET_EXTERN_COROUTINE(_1, _2, NAME, ...) NAME
125 #define EXTERN_COROUTINE1(name) \
126 struct Coroutine_##name : ace_routine::Coroutine { \
127 Coroutine_##name(); \
128 int runCoroutine() override; \
130 extern Coroutine_##name name
133 #define EXTERN_COROUTINE2(className, name) \
134 struct className##_##name : className { \
135 className##_##name(); \
136 int runCoroutine() override; \
138 extern className##_##name name
141 #define COROUTINE_BEGIN() \
142 void* p = this->getJump(); \
143 if (p != nullptr) { \
151 #define COROUTINE_LOOP() \
159 #define COROUTINE_YIELD_INTERNAL() \
161 __label__ jumpLabel; \
162 this->setJump(&& jumpLabel); \
168 #define COROUTINE_YIELD() \
170 this->setYielding(); \
171 COROUTINE_YIELD_INTERNAL(); \
172 this->setRunning(); \
185 #define COROUTINE_AWAIT(condition) \
187 this->setYielding(); \
189 COROUTINE_YIELD_INTERNAL(); \
190 } while (!(condition)); \
191 this->setRunning(); \
209 #define COROUTINE_DELAY(delayMillis) \
211 this->setDelayMillis(delayMillis); \
212 this->setDelaying(); \
214 COROUTINE_YIELD_INTERNAL(); \
215 } while (!this->isDelayExpired()); \
216 this->setRunning(); \
220 #define COROUTINE_DELAY_MICROS(delayMicros) \
222 this->setDelayMicros(delayMicros); \
223 this->setDelaying(); \
225 COROUTINE_YIELD_INTERNAL(); \
226 } while (!this->isDelayMicrosExpired()); \
227 this->setRunning(); \
245 #define COROUTINE_DELAY_SECONDS(delaySeconds) \
247 this->setDelaySeconds(delaySeconds); \
248 this->setDelaying(); \
250 COROUTINE_YIELD_INTERNAL(); \
251 } while (!this->isDelaySecondsExpired()); \
252 this->setRunning(); \
259 #define COROUTINE_END() \
261 __label__ jumpLabel; \
263 this->setJump(&& jumpLabel); \
268 namespace ace_routine {
271 extern const __FlashStringHelper*
const sStatusStrings[] PROGMEM;
291 template <
typename T_CLOCK,
typename T_DELAY>
294 friend class ::AceRoutineTest_statusStrings;
295 friend class ::SuspendTest_suspendAndResume;
369 void setName(
const __FlashStringHelper* name) {
379 return (
const __FlashStringHelper*)
mName;
393 ace_common::PrintStr<64> pname;
395 if (
mName ==
nullptr) {
397 pname.print((uintptr_t)
this, 16);
399 pname.print((
const char*)
mName);
401 pname.print((
const __FlashStringHelper*)
mName);
406 if (pname.length() < maxLen) {
407 printer.write(pname.cstr());
408 for (uint8_t i = pname.length(); i < maxLen; i++) {
415 printer.write((
const uint8_t*) pname.cstr(), maxLen);
418 printer.write(pname.cstr());
652 printer.print((
const __FlashStringHelper*)
653 pgm_read_ptr(&sStatusStrings[
mStatus]));
743 return T_CLOCK::millis();
752 return T_CLOCK::micros();
762 return T_CLOCK::seconds();
776 void insertAtRoot() {
void printNameTo(Print &printer, uint8_t maxLen=0) const
Print name to the given Printer.
static const uint8_t kNameTypeFString
Coroutine name is a const __FlashStringHelper* f-string.
virtual void updateElapsedMicros(uint32_t micros)=0
Process the completion of the runCoroutine() method which took micros microseconds.
CoroutineTemplate * mNext
Pointer to the next coroutine in a singly-linked list.
Status getStatus() const
Return the status of the coroutine.
bool isDelaying() const
The coroutine returned using COROUTINE_DELAY().
void setEnding()
Set the kStatusEnding state.
void * getJump() const
Pointer to label where execute will start on the next call to runCoroutine().
static const Status kStatusYielding
Coroutine returned using the COROUTINE_YIELD() statement.
bool isDone() const
The coroutine is either Ending or Terminated.
const char * getCName() const
Get name of the coroutine assuming it's a c-string.
void setName(const char *name)
Set the name of the coroutine to the given c-string.
uint8_t getNameType() const
Return the type of the name string, either kNameTypeCString or kNameTypeFString.
bool isYielding() const
The coroutine returned using COROUTINE_YIELD().
void setDelayMicros(T_DELAY delayMicros)
Configure the delay timer for delayMicros.
~CoroutineTemplate()=default
Destructor.
CoroutineTemplate ** getNext()
Return the next pointer as a pointer to the pointer, similar to getRoot().
void setYielding()
Set the kStatusDelaying state.
void setJump(void *jumpPoint)
Pointer to label where execute will start on the next call to runCoroutine().
static CoroutineTemplate ** getRoot()
Get the pointer to the root pointer.
CoroutineTemplate()
Constructor.
uint8_t mNameType
String type of the coroutine mName.
static const uint8_t kNameTypeCString
Coroutine name is a const char* c-string.
CoroutineProfiler * getProfiler() const
Get the profiler.
void suspend()
Suspend the coroutine at the next scheduler iteration.
virtual int runCoroutine()=0
The body of the coroutine.
Base class of all coroutines.
void setupCoroutine(const char *) ACE_ROUTINE_DEPRECATED
Deprecated method that does nothing.
static unsigned long coroutineMillis()
Returns the current millisecond clock.
void setProfiler(CoroutineProfiler *profiler)
Set the profiler.
Status mStatus
Run-state of the coroutine.
void setName(const __FlashStringHelper *name)
Set the name of the coroutine to the given f-string.
bool isDelayMicrosExpired() const
Check if delay micros time is over.
An interface class for profiling classes that can track the elapsed time consumed by Coroutine::runCo...
void setDelaying()
Set the kStatusDelaying state.
const void * mName
Name of the coroutine, either (const char*) or (const __FlashStringHelper*).
void setDelayMillis(T_DELAY delayMillis)
Configure the delay timer for delayMillis.
bool isDelaySecondsExpired() const
Check if delay seconds time is over.
void resume()
Add a Suspended coroutine into the head of the scheduler linked list, and change the state to Yieldin...
static const Status kStatusSuspended
Coroutine has been suspended using suspend() and the scheduler should remove it from the queue upon t...
uint8_t Status
The execution status of the coroutine, corresponding to the COROUTINE_YIELD(), COROUTINE_DELAY(),...
void setRunning()
Set the kStatusRunning state.
static const Status kStatusEnding
Coroutine executed the COROUTINE_END() statement.
static unsigned long coroutineSeconds()
Returns the current clock in unit of seconds, truncated to the lower 16-bits.
void reset()
Reset the coroutine to its initial state.
static const Status kStatusTerminated
Coroutine has ended and no longer in the scheduler queue.
bool isRunning() const
The coroutine is currently running.
T_DELAY mDelayStart
Start time provided by COROUTINE_DELAY(), COROUTINE_DELAY_MICROS(), or COROUTINE_DELAY_SECONDS().
const __FlashStringHelper * getFName() const
Get name of the coroutine assuming it's an f-string.
int runCoroutineWithProfiler()
This is a variant of runCoroutine() which measures the execution time of runCoroutine() and updates t...
void setDelaySeconds(T_DELAY delaySeconds)
Configure the delay timer for delaySeconds.
virtual void setupCoroutine()
Perform coroutine initialization.
bool isDelayExpired() const
Check if delay millis time is over.
static unsigned long coroutineMicros()
Returns the current microseconds clock.
Class that manages instances of the Coroutine class, and executes them in a round-robin fashion.
T_DELAY mDelayDuration
Delay time specified by COROUTINE_DELAY(), COROUTINE_DELAY_MICROS() or, COROUTINE_DELAY_SECONDS().
CoroutineProfiler * mProfiler
Pointer to a profiler instance, either static or on the heap.
void setTerminated()
Set status to indicate that the Coroutine has been removed from the Scheduler queue.
bool isSuspended() const
The coroutine was suspended with a call to suspend().
bool isTerminated() const
The coroutine was terminated by the scheduler with a call to setTerminated().
bool isEnding() const
The coroutine returned using COROUTINE_END().
void * mJumpPoint
Address of the label used by the computed-goto.
void setupCoroutine(const __FlashStringHelper *) ACE_ROUTINE_DEPRECATED
Deprecated method that does nothing.
#define ACE_ROUTINE_DEPRECATED
Macro that indicates a deprecation.
static const Status kStatusDelaying
Coroutine returned using the COROUTINE_DELAY() statement.
void statusPrintTo(Print &printer)
Print the human-readable string of the Status.
static const Status kStatusRunning
Coroutine is currenly running.