25 #ifndef ACE_ROUTINE_COROUTINE_H 26 #define ACE_ROUTINE_COROUTINE_H 33 class AceRoutineTest_statusStrings;
66 #define COROUTINE(...) \ 67 GET_COROUTINE(__VA_ARGS__, COROUTINE2, COROUTINE1)(__VA_ARGS__) 69 #define GET_COROUTINE(_1, _2, NAME, ...) NAME 71 #define COROUTINE1(name) \ 72 struct Coroutine_##name : ace_routine::Coroutine { \ 74 int runCoroutine() override \ 75 __attribute__((__noinline__,__noclone__)); \ 77 Coroutine_##name :: Coroutine_##name() { \ 78 setupCoroutine(ACE_ROUTINE_F(#name)); \ 80 int Coroutine_##name :: runCoroutine() 82 #define COROUTINE2(className, name) \ 83 struct className##_##name : className { \ 84 className##_##name(); \ 85 int runCoroutine() override \ 86 __attribute__((__noinline__,__noclone__)); \ 88 className##_##name :: className##_##name() { \ 89 setupCoroutine(ACE_ROUTINE_F(#name)); \ 91 int className##_##name :: runCoroutine() 101 #define EXTERN_COROUTINE(...) \ 102 GET_EXTERN_COROUTINE(\ 103 __VA_ARGS__, EXTERN_COROUTINE2, EXTERN_COROUTINE1)(__VA_ARGS__) 105 #define GET_EXTERN_COROUTINE(_1, _2, NAME, ...) NAME 107 #define EXTERN_COROUTINE1(name) \ 108 struct Coroutine_##name : ace_routine::Coroutine { \ 109 Coroutine_##name(); \ 110 int runCoroutine() override \ 111 __attribute__((__noinline__,__noclone__)); \ 113 extern Coroutine_##name name 115 #define EXTERN_COROUTINE2(className, name) \ 116 struct className##_##name : className { \ 117 className##_##name(); \ 118 int runCoroutine() override \ 119 __attribute__((__noinline__,__noclone__)); \ 121 extern className##_##name name 124 #define COROUTINE_BEGIN() \ 125 void* p = getJump(); \ 126 if (p != nullptr) { \ 134 #define COROUTINE_LOOP() \ 138 #define COROUTINE_YIELD_INTERNAL() \ 140 __label__ jumpLabel; \ 141 setJump(&& jumpLabel); \ 147 #define COROUTINE_YIELD() \ 150 COROUTINE_YIELD_INTERNAL(); \ 164 #define COROUTINE_AWAIT(condition) \ 168 COROUTINE_YIELD_INTERNAL(); \ 169 } while (!(condition)); \ 189 #define COROUTINE_DELAY(delayMillis) \ 191 setDelayMillis(delayMillis); \ 194 COROUTINE_YIELD_INTERNAL(); \ 195 } while (!isDelayExpired()); \ 200 #define COROUTINE_DELAY_MICROS(delayMicros) \ 202 setDelayMicros(delayMicros); \ 205 COROUTINE_YIELD_INTERNAL(); \ 206 } while (!isDelayExpired()); \ 211 #define COROUTINE_DELAY_SECONDS(delaySeconds) \ 213 setDelaySeconds(delaySeconds); \ 216 COROUTINE_YIELD_INTERNAL(); \ 217 } while (!isDelayExpired()); \ 225 #define COROUTINE_END() \ 227 __label__ jumpLabel; \ 229 setJump(&& jumpLabel); \ 249 unsigned long x = (n >> 8);
250 unsigned long y = (x >> 8);
251 unsigned long z = (y >> 8);
252 return (x >> 2) + 3 * (y >> 1) + 9 * z;
262 friend class ::AceRoutineTest_statusStrings;
292 virtual int runCoroutine() = 0;
298 virtual unsigned long coroutineMillis()
const;
304 virtual unsigned long coroutineMicros()
const;
312 virtual unsigned long coroutineSeconds()
const;
325 if (isDone())
return;
326 mStatus = kStatusSuspended;
339 switch (mDelayType) {
341 case kDelayTypeMillis: {
342 uint16_t elapsedMillis = coroutineMillis() - mDelayStart;
343 return elapsedMillis >= mDelayDuration;
345 case kDelayTypeMicros: {
346 uint16_t elapsedMicros = coroutineMicros() - mDelayStart;
347 return elapsedMicros >= mDelayDuration;
349 case kDelayTypeSeconds: {
350 uint16_t elapsedSeconds = coroutineSeconds() - mDelayStart;
351 return elapsedSeconds >= mDelayDuration;
360 bool isYielding()
const {
return mStatus == kStatusYielding; }
363 bool isDelaying()
const {
return mStatus == kStatusDelaying; }
366 bool isRunning()
const {
return mStatus == kStatusRunning; }
373 bool isEnding()
const {
return mStatus == kStatusEnding; }
389 return mStatus == kStatusEnding || mStatus == kStatusTerminated;
408 mStatus = kStatusYielding;
427 mStatus = kStatusYielding;
470 static const Status kStatusSuspended = 0;
473 static const Status kStatusYielding = 1;
476 static const Status kStatusDelaying = 2;
479 static const Status kStatusRunning = 3;
482 static const Status kStatusEnding = 4;
485 static const Status kStatusTerminated = 5;
488 static const uint8_t kDelayTypeMillis = 0;
491 static const uint8_t kDelayTypeMicros = 1;
494 static const uint8_t kDelayTypeSeconds = 2;
516 printer.print(sStatusStrings[mStatus]);
523 void setJump(
void* jumpPoint) { mJumpPoint = jumpPoint; }
554 mDelayType = kDelayTypeMillis;
555 mDelayStart = coroutineMillis();
556 mDelayDuration = (delayMillis >= UINT16_MAX / 2)
566 mDelayType = kDelayTypeMicros;
567 mDelayStart = coroutineMicros();
568 mDelayDuration = (delayMicros >= UINT16_MAX / 2)
578 mDelayType = kDelayTypeSeconds;
579 mDelayStart = coroutineSeconds();
580 mDelayDuration = (delaySeconds >= UINT16_MAX / 2)
600 static const __FlashStringHelper*
const sStatusStrings[];
618 void* mJumpPoint =
nullptr;
619 Status mStatus = kStatusSuspended;
621 uint16_t mDelayStart;
622 uint16_t mDelayDuration;
void setupCoroutine(const char *name)
Initialize the coroutine for the CoroutineScheduler, set it to Yielding state, and add it to the link...
void setDelaySeconds(uint16_t delaySeconds)
Configure the delay timer for delaySeconds.
Class that manages instances of the Coroutine class, and executes them in a round-robin fashion...
void setTerminated()
Set status to indicate that the Coroutine has been removed from the Scheduler queue.
void setJump(void *jumpPoint)
Pointer to label where execute will start on the next call to runCoroutine().
void setDelayMillis(uint16_t delayMillis)
Configure the delay timer for delayMillis.
void * getJump() const
Pointer to label where execute will start on the next call to runCoroutine().
bool isDone() const
The coroutine is either Ending or Terminated.
const FCString & getName() const
Human-readable name of the coroutine.
bool isTerminated() const
The coroutine was terminated by the scheduler with a call to setTerminated().
bool isDelaying() const
The coroutine returned using COROUTINE_DELAY().
bool isEnding() const
The coroutine returned using COROUTINE_END().
void setupCoroutine(const __FlashStringHelper *name)
Same as setupCoroutine(const char*) except using flash string type.
Status getStatus() const
Return the status of the coroutine.
uint8_t Status
The execution status of the coroutine, corresponding to the COROUTINE_YIELD(), COROUTINE_DELAY(), COROUTINE_AWAIT() and COROUTINE_END() macros.
A union of (const char*) and (const __FlashStringHelper*) with a discriminator.
unsigned long udiv1000(unsigned long n)
Approximate division by 1000.
void setYielding()
Set the kStatusDelaying state.
bool isRunning() const
The coroutine is currently running.
virtual ~Coroutine()
Destructor.
bool isYielding() const
The coroutine returned using COROUTINE_YIELD().
void setRunning()
Set the kStatusRunning state.
void statusPrintTo(Print &printer)
Print the human-readable string of the Status.
void setEnding()
Set the kStatusEnding state.
bool isSuspended() const
The coroutine was suspended with a call to suspend().
bool isDelayExpired()
Check if delay time is over.
Coroutine ** getNext()
Return the next pointer as a pointer to the pointer, similar to getRoot().
Base class of all coroutines.
Various macros to smooth over the differences among the various platforms with regards to their suppo...
void setDelaying()
Set the kStatusDelaying state.
void setDelayMicros(uint16_t delayMicros)
Configure the delay timer for delayMicros.
void suspend()
Suspend the coroutine at the next scheduler iteration.