25 #ifndef ACE_ROUTINE_COROUTINE_H 26 #define ACE_ROUTINE_COROUTINE_H 64 #define COROUTINE(...) \ 65 GET_COROUTINE(__VA_ARGS__, COROUTINE2, COROUTINE1)(__VA_ARGS__) 67 #define GET_COROUTINE(_1, _2, NAME, ...) NAME 69 #define COROUTINE1(name) \ 70 struct Coroutine_##name : ace_routine::Coroutine { \ 72 virtual int run() override \ 73 __attribute__((__noinline__,__noclone__)); \ 75 Coroutine_##name :: Coroutine_##name() { \ 76 init(ACE_ROUTINE_F(#name)); \ 78 int Coroutine_##name :: run() 80 #define COROUTINE2(className, name) \ 81 struct className##_##name : className { \ 82 className##_##name(); \ 83 virtual int run() override \ 84 __attribute__((__noinline__,__noclone__)); \ 86 className##_##name :: className##_##name() { \ 87 init(ACE_ROUTINE_F(#name)); \ 89 int className##_##name :: run() 99 #define EXTERN_COROUTINE(...) \ 100 GET_EXTERN_COROUTINE(\ 101 __VA_ARGS__, EXTERN_COROUTINE2, EXTERN_COROUTINE1)(__VA_ARGS__) 103 #define GET_EXTERN_COROUTINE(_1, _2, NAME, ...) NAME 105 #define EXTERN_COROUTINE1(name) \ 106 struct Coroutine_##name : ace_routine::Coroutine { \ 107 Coroutine_##name(); \ 108 virtual int run() override \ 109 __attribute__((__noinline__,__noclone__)); \ 111 extern Coroutine_##name name 113 #define EXTERN_COROUTINE2(className, name) \ 114 struct className##_##name : className { \ 115 className##_##name(); \ 116 virtual int run() override \ 117 __attribute__((__noinline__,__noclone__)); \ 119 extern className##_##name name 122 #define COROUTINE_BEGIN() \ 123 void* p = getJump(); \ 124 if (p != nullptr) { \ 132 #define COROUTINE_LOOP() \ 136 #define COROUTINE_YIELD_INTERNAL() \ 138 __label__ jumpLabel; \ 139 setJump(&& jumpLabel); \ 145 #define COROUTINE_YIELD() \ 148 COROUTINE_YIELD_INTERNAL(); \ 164 #define COROUTINE_AWAIT(condition) \ 166 while (!(condition)) { \ 168 COROUTINE_YIELD_INTERNAL(); \ 188 #define COROUTINE_DELAY(delayMillis) \ 190 setDelay(delayMillis); \ 191 while (!isDelayExpired()) { \ 193 COROUTINE_YIELD_INTERNAL(); \ 202 #define COROUTINE_END() \ 204 __label__ jumpLabel; \ 206 setJump(&& jumpLabel); \ 248 virtual int run() = 0;
254 virtual unsigned long millis()
const;
281 uint16_t elapsedMillis =
millis() - mDelayStartMillis;
282 return elapsedMillis >= mDelayDurationMillis;
399 void init(
const __FlashStringHelper* name) {
409 void setJump(
void* jumpPoint) { mJumpPoint = jumpPoint; }
438 mDelayStartMillis =
millis();
439 mDelayDurationMillis = (delayMillisDuration >= UINT16_MAX / 2)
441 : delayMillisDuration;
474 void* mJumpPoint =
nullptr;
476 uint16_t mDelayStartMillis;
477 uint16_t mDelayDurationMillis;
void resume()
Add a Suspended coroutine into the head of the scheduler linked list, and change the state to Yieldin...
bool isAwaiting() const
The coroutine returned using COROUTINE_AWAIT().
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.
static const Status kStatusEnding
Coroutine executed the COROUTINE_END() statement.
void setJump(void *jumpPoint)
Pointer to label where execute will start on the next call to run().
void init(const __FlashStringHelper *name)
Same as init(const char*) except using flash string type.
void * getJump() const
Pointer to label where execute will start on the next call to run().
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().
static const Status kStatusRunning
Coroutine is currenly running.
bool isEnding() const
The coroutine returned using COROUTINE_END().
static const Status kStatusYielding
Coroutine returned using the COROUTINE_YIELD() statement.
virtual unsigned long millis() const
Returns the current millisecond clock.
static const Status kStatusSuspended
Coroutine has been suspended using suspend() and the scheduler should remove it from the queue upon t...
Status getStatus() const
Return the status of the coroutine.
static const Status kStatusTerminated
Coroutine has ended and no longer in the scheduler queue.
uint8_t Status
The execution status of the coroutine, corresponding to the COROUTINE_YIELD(), COROUTINE_DELAY(), COROUTINE_AWAIT() and COROUTINE_END() macros.
virtual int run()=0
The body of the coroutine.
A union of (const char*) and (const __FlashStringHelper*) with a discriminator.
static const Status kStatusDelaying
Coroutine returned using the COROUTINE_DELAY() statement.
void setDelay(uint16_t delayMillisDuration)
Configure the delay timer.
void setYielding()
Set the kStatusDelaying state.
bool isRunning() const
The coroutine is currently running.
static const Status kStatusAwaiting
Coroutine returned using the COROUTINE_AWAIT() statement.
bool isYielding() const
The coroutine returned using COROUTINE_YIELD().
void setRunning()
Set the kStatusRunning state.
void init(const char *name)
Initialize the coroutine, set it to Yielding state, and add it to the linked list of coroutines...
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.
static Coroutine ** getRoot()
Get the pointer to the root pointer.
Various macros to smooth over the differences among the various platforms with regards to their suppo...
void setAwaiting()
Set the kStatusAwaiting state.
void setDelaying()
Set the kStatusDelaying state.
void suspend()
Suspend the coroutine at the next scheduler iteration.