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;
274 template <
typename T>
class CoroutineSchedulerTemplate;
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() {
#define ACE_ROUTINE_DEPRECATED
Macro that indicates a deprecation.
An interface class for profiling classes that can track the elapsed time consumed by Coroutine::runCo...
virtual void updateElapsedMicros(uint32_t micros)=0
Process the completion of the runCoroutine() method which took micros microseconds.
Class that manages instances of the Coroutine class, and executes them in a round-robin fashion.
Base class of all coroutines.
CoroutineTemplate ** getNext()
Return the next pointer as a pointer to the pointer, similar to getRoot().
void setName(const char *name)
Set the name of the coroutine to the given c-string.
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...
void reset()
Reset the coroutine to its initial state.
void setDelayMicros(T_DELAY delayMicros)
Configure the delay timer for delayMicros.
void * getJump() const
Pointer to label where execute will start on the next call to runCoroutine().
void setDelayMillis(T_DELAY delayMillis)
Configure the delay timer for delayMillis.
static const Status kStatusEnding
Coroutine executed the COROUTINE_END() statement.
static unsigned long coroutineMicros()
Returns the current microseconds clock.
void setJump(void *jumpPoint)
Pointer to label where execute will start on the next call to runCoroutine().
void setupCoroutine(const char *) ACE_ROUTINE_DEPRECATED
Deprecated method that does nothing.
uint8_t getNameType() const
Return the type of the name string, either kNameTypeCString or kNameTypeFString.
const char * getCName() const
Get name of the coroutine assuming it's a c-string.
CoroutineProfiler * mProfiler
Pointer to a profiler instance, either static or on the heap.
int runCoroutineWithProfiler()
This is a variant of runCoroutine() which measures the execution time of runCoroutine() and updates t...
void suspend()
Suspend the coroutine at the next scheduler iteration.
T_DELAY mDelayDuration
Delay time specified by COROUTINE_DELAY(), COROUTINE_DELAY_MICROS() or, COROUTINE_DELAY_SECONDS().
bool isTerminated() const
The coroutine was terminated by the scheduler with a call to setTerminated().
void printNameTo(Print &printer, uint8_t maxLen=0) const
Print name to the given Printer.
virtual int runCoroutine()=0
The body of the coroutine.
void setName(const __FlashStringHelper *name)
Set the name of the coroutine to the given f-string.
bool isDelaying() const
The coroutine returned using COROUTINE_DELAY().
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 void * mName
Name of the coroutine, either (const char*) or (const __FlashStringHelper*).
static const Status kStatusYielding
Coroutine returned using the COROUTINE_YIELD() statement.
void setDelaying()
Set the kStatusDelaying state.
~CoroutineTemplate()=default
Destructor.
uint8_t Status
The execution status of the coroutine, corresponding to the COROUTINE_YIELD(), COROUTINE_DELAY(),...
Status getStatus() const
Return the status of the coroutine.
Status mStatus
Run-state of the coroutine.
void setRunning()
Set the kStatusRunning state.
bool isYielding() const
The coroutine returned using COROUTINE_YIELD().
bool isSuspended() const
The coroutine was suspended with a call to suspend().
static CoroutineTemplate ** getRoot()
Get the pointer to the root pointer.
void setupCoroutine(const __FlashStringHelper *) ACE_ROUTINE_DEPRECATED
Deprecated method that does nothing.
void setYielding()
Set the kStatusDelaying state.
void * mJumpPoint
Address of the label used by the computed-goto.
uint8_t mNameType
String type of the coroutine mName.
void setDelaySeconds(T_DELAY delaySeconds)
Configure the delay timer for delaySeconds.
void setEnding()
Set the kStatusEnding state.
static const uint8_t kNameTypeCString
Coroutine name is a const char* c-string.
virtual void setupCoroutine()
Perform coroutine initialization.
CoroutineProfiler * getProfiler() const
Get the profiler.
void setTerminated()
Set status to indicate that the Coroutine has been removed from the Scheduler queue.
bool isDelayMicrosExpired() const
Check if delay micros time is over.
static unsigned long coroutineMillis()
Returns the current millisecond clock.
bool isDone() const
The coroutine is either Ending or Terminated.
bool isEnding() const
The coroutine returned using COROUTINE_END().
void setProfiler(CoroutineProfiler *profiler)
Set the profiler.
bool isDelayExpired() const
Check if delay millis time is over.
CoroutineTemplate * mNext
Pointer to the next coroutine in a singly-linked list.
const __FlashStringHelper * getFName() const
Get name of the coroutine assuming it's an f-string.
CoroutineTemplate()
Constructor.
static const Status kStatusTerminated
Coroutine has ended and no longer in the scheduler queue.
static unsigned long coroutineSeconds()
Returns the current clock in unit of seconds, truncated to the lower 16-bits.
static const Status kStatusRunning
Coroutine is currenly running.
static const uint8_t kNameTypeFString
Coroutine name is a const __FlashStringHelper* f-string.
static const Status kStatusSuspended
Coroutine has been suspended using suspend() and the scheduler should remove it from the queue upon t...
static const Status kStatusDelaying
Coroutine returned using the COROUTINE_DELAY() statement.
void statusPrintTo(Print &printer)
Print the human-readable string of the Status.
Various macros to smooth over the differences among the various platforms with regards to their suppo...