AceRoutine  1.5.0
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
Coroutine.h
Go to the documentation of this file.
1 /*
2 MIT License
3 
4 Copyright (c) 2018 Brian T. Park
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 
25 #ifndef ACE_ROUTINE_COROUTINE_H
26 #define ACE_ROUTINE_COROUTINE_H
27 
28 #include <stdint.h> // UINT16_MAX
29 #include <Print.h> // Print
30 #include <AceCommon.h> // PrintStr<>
31 #include "CoroutineProfiler.h"
32 #include "ClockInterface.h"
33 #include "compat.h" // PROGMEM
34 
35 class __FlashStringHelper;
36 class AceRoutineTest_statusStrings;
37 class SuspendTest_suspendAndResume;
38 
57 // https://stackoverflow.com/questions/295120
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)
63 #else
64  #pragma message("WARNING: Implement ACE_ROUTINE_DEPRECATED for this compiler")
65  #define ACE_ROUTINE_DEPRECATED
66 #endif
67 
81 #define COROUTINE(...) \
82  GET_COROUTINE(__VA_ARGS__, COROUTINE2, COROUTINE1)(__VA_ARGS__)
83 
85 #define GET_COROUTINE(_1, _2, NAME, ...) NAME
86 
88 #define COROUTINE1(name) \
89 struct Coroutine_##name : ace_routine::Coroutine { \
90  Coroutine_##name(); \
91  int runCoroutine() override; \
92 } name; \
93 Coroutine_##name :: Coroutine_##name() { \
94 } \
95 int Coroutine_##name :: runCoroutine()
96 
98 #define COROUTINE2(className, name) \
99 struct className##_##name : className { \
100  className##_##name(); \
101  int runCoroutine() override; \
102 } name; \
103 className##_##name :: className##_##name() { \
104 } \
105 int className##_##name :: runCoroutine()
106 
115 #define EXTERN_COROUTINE(...) \
116  GET_EXTERN_COROUTINE(\
117  __VA_ARGS__, EXTERN_COROUTINE2, EXTERN_COROUTINE1)(__VA_ARGS__)
118 
122 #define GET_EXTERN_COROUTINE(_1, _2, NAME, ...) NAME
123 
125 #define EXTERN_COROUTINE1(name) \
126 struct Coroutine_##name : ace_routine::Coroutine { \
127  Coroutine_##name(); \
128  int runCoroutine() override; \
129 }; \
130 extern Coroutine_##name name
131 
133 #define EXTERN_COROUTINE2(className, name) \
134 struct className##_##name : className { \
135  className##_##name(); \
136  int runCoroutine() override; \
137 }; \
138 extern className##_##name name
139 
141 #define COROUTINE_BEGIN() \
142  void* p = this->getJump(); \
143  if (p != nullptr) { \
144  goto *p; \
145  }
146 
151 #define COROUTINE_LOOP() \
152  COROUTINE_BEGIN(); \
153  while (true) \
154 
155 
159 #define COROUTINE_YIELD_INTERNAL() \
160  do { \
161  __label__ jumpLabel; \
162  this->setJump(&& jumpLabel); \
163  return 0; \
164  jumpLabel: ; \
165  } while (false)
166 
168 #define COROUTINE_YIELD() \
169  do { \
170  this->setYielding(); \
171  COROUTINE_YIELD_INTERNAL(); \
172  this->setRunning(); \
173  } while (false)
174 
185 #define COROUTINE_AWAIT(condition) \
186  do { \
187  this->setYielding(); \
188  do { \
189  COROUTINE_YIELD_INTERNAL(); \
190  } while (!(condition)); \
191  this->setRunning(); \
192  } while (false)
193 
209 #define COROUTINE_DELAY(delayMillis) \
210  do { \
211  this->setDelayMillis(delayMillis); \
212  this->setDelaying(); \
213  do { \
214  COROUTINE_YIELD_INTERNAL(); \
215  } while (!this->isDelayExpired()); \
216  this->setRunning(); \
217  } while (false)
218 
220 #define COROUTINE_DELAY_MICROS(delayMicros) \
221  do { \
222  this->setDelayMicros(delayMicros); \
223  this->setDelaying(); \
224  do { \
225  COROUTINE_YIELD_INTERNAL(); \
226  } while (!this->isDelayMicrosExpired()); \
227  this->setRunning(); \
228  } while (false)
229 
245 #define COROUTINE_DELAY_SECONDS(delaySeconds) \
246  do { \
247  this->setDelaySeconds(delaySeconds); \
248  this->setDelaying(); \
249  do { \
250  COROUTINE_YIELD_INTERNAL(); \
251  } while (!this->isDelaySecondsExpired()); \
252  this->setRunning(); \
253  } while (false)
254 
259 #define COROUTINE_END() \
260  do { \
261  __label__ jumpLabel; \
262  this->setEnding(); \
263  this->setJump(&& jumpLabel); \
264  jumpLabel: ; \
265  return 0; \
266  } while (false)
267 
268 namespace ace_routine {
269 
271 extern const __FlashStringHelper* const sStatusStrings[] PROGMEM;
272 
273 // Forward declaration of CoroutineSchedulerTemplate<T>
274 template <typename T> class CoroutineSchedulerTemplate;
275 
291 template <typename T_CLOCK, typename T_DELAY>
293  friend class CoroutineSchedulerTemplate<CoroutineTemplate<T_CLOCK, T_DELAY>>;
294  friend class ::AceRoutineTest_statusStrings;
295  friend class ::SuspendTest_suspendAndResume;
296 
297  public:
299  static const uint8_t kNameTypeCString = 0;
300 
302  static const uint8_t kNameTypeFString = 1;
303 
304  public:
315  virtual int runCoroutine() = 0;
316 
331  virtual void setupCoroutine() {}
332 
345  if (mProfiler) {
346  uint32_t startMicros = coroutineMicros();
347  runCoroutine();
348  uint32_t elapsedMicros = coroutineMicros() - startMicros;
349  mProfiler->updateElapsedMicros(elapsedMicros);
350  return 0;
351  } else {
352  return runCoroutine();
353  }
354  }
355 
360  uint8_t getNameType() const { return mNameType; }
361 
363  void setName(const char* name) {
365  mName = name;
366  }
367 
369  void setName(const __FlashStringHelper* name) {
371  mName = name;
372  }
373 
375  const char* getCName() const { return (const char*) mName; }
376 
378  const __FlashStringHelper* getFName() const {
379  return (const __FlashStringHelper*) mName;
380  }
381 
389  void printNameTo(Print& printer, uint8_t maxLen = 0) const {
390  // Need to go through this contortion because vsnprintf() does not support
391  // flash string parameters, so I can't use something like "%12.12s" with
392  // a flash string.
393  ace_common::PrintStr<64> pname;
394 
395  if (mName == nullptr) {
396  pname.print("0x");
397  pname.print((uintptr_t) this, 16);
398  } else if (mNameType == kNameTypeCString) {
399  pname.print((const char*) mName);
400  } else {
401  pname.print((const __FlashStringHelper*) mName);
402  }
403 
404  // Print name, truncated to maxLen or padded to maxLen.
405  if (maxLen) {
406  if (pname.length() < maxLen) {
407  printer.write(pname.cstr());
408  for (uint8_t i = pname.length(); i < maxLen; i++) {
409  printer.write(' ');
410  }
411  } else {
412  // NOTE: Must cast to (const uint8_t*) because the ATtiny85 core does
413  // not have a version of write() that accepts a (const char*), in
414  // contrast to every other Arduino Core.
415  printer.write((const uint8_t*) pname.cstr(), maxLen);
416  }
417  } else {
418  printer.write(pname.cstr());
419  }
420  }
421 
432  void suspend() {
433  if (isDone()) return;
435  }
436 
443  void resume() {
444  if (mStatus != kStatusSuspended) return;
445 
446  // We lost the original state of the coroutine when suspend() was called
447  // but the coroutine will automatically go back into the original state
448  // when Coroutine::runCoroutine() is called because COROUTINE_YIELD(),
449  // COROUTINE_DELAY() and COROUTINE_AWAIT() are written to restore their
450  // status.
452  }
453 
467  void reset() {
469  mJumpPoint = nullptr;
470  }
471 
473  bool isDelayExpired() const {
474  T_DELAY nowMillis = coroutineMillis();
475  T_DELAY elapsed = nowMillis - mDelayStart;
476  return elapsed >= mDelayDuration;
477  }
478 
480  bool isDelayMicrosExpired() const {
481  T_DELAY nowMicros = coroutineMicros();
482  T_DELAY elapsed = nowMicros - mDelayStart;
483  return elapsed >= mDelayDuration;
484  }
485 
487  bool isDelaySecondsExpired() const {
488  T_DELAY nowSeconds = coroutineSeconds();
489  T_DELAY elapsed = nowSeconds - mDelayStart;
490  return elapsed >= mDelayDuration;
491  }
492 
494  bool isSuspended() const { return mStatus == kStatusSuspended; }
495 
497  bool isYielding() const { return mStatus == kStatusYielding; }
498 
500  bool isDelaying() const { return mStatus == kStatusDelaying; }
501 
503  bool isRunning() const { return mStatus == kStatusRunning; }
504 
510  bool isEnding() const { return mStatus == kStatusEnding; }
511 
518  bool isTerminated() const { return mStatus == kStatusTerminated; }
519 
525  bool isDone() const {
527  }
528 
535  void setupCoroutine(const char* /*name*/) ACE_ROUTINE_DEPRECATED {}
536 
543  void setupCoroutine(const __FlashStringHelper* /*name*/)
545 
547  void setProfiler(CoroutineProfiler* profiler) { mProfiler = profiler; }
548 
551 
558  // Use a static variable inside a function to solve the static
559  // initialization ordering problem.
560  static CoroutineTemplate* root;
561  return &root;
562  }
563 
570  CoroutineTemplate** getNext() { return &mNext; }
571 
572  protected:
603  typedef uint8_t Status;
604 
611  static const Status kStatusSuspended = 0;
612 
614  static const Status kStatusYielding = 1;
615 
617  static const Status kStatusDelaying = 2;
618 
620  static const Status kStatusRunning = 3;
621 
623  static const Status kStatusEnding = 4;
624 
626  static const Status kStatusTerminated = 5;
627 
630  insertAtRoot();
631  }
632 
645  ~CoroutineTemplate() = default;
646 
648  Status getStatus() const { return mStatus; }
649 
651  void statusPrintTo(Print& printer) {
652  printer.print((const __FlashStringHelper*)
653  pgm_read_ptr(&sStatusStrings[mStatus]));
654  }
655 
660  void setJump(void* jumpPoint) { mJumpPoint = jumpPoint; }
661 
666  void* getJump() const { return mJumpPoint; }
667 
670 
673 
676 
679 
685 
699  void setDelayMillis(T_DELAY delayMillis) {
701 
702  // If delayMillis is a compile-time constant, the compiler seems to
703  // completely optimize away this bounds checking code.
704  mDelayDuration = (delayMillis >= UINT16_MAX / 2)
705  ? UINT16_MAX / 2
706  : delayMillis;
707  }
708 
713  void setDelayMicros(T_DELAY delayMicros) {
715 
716  // If delayMicros is a compile-time constant, the compiler seems to
717  // completely optimize away this bounds checking code.
718  mDelayDuration = (delayMicros >= UINT16_MAX / 2)
719  ? UINT16_MAX / 2
720  : delayMicros;
721  }
722 
727  void setDelaySeconds(T_DELAY delaySeconds) {
729 
730  // If delaySeconds is a compile-time constant, the compiler seems to
731  // completely optimize away this bounds checking code.
732  mDelayDuration = (delaySeconds >= UINT16_MAX / 2)
733  ? UINT16_MAX / 2
734  : delaySeconds;
735  }
736 
742  static unsigned long coroutineMillis() {
743  return T_CLOCK::millis();
744  }
745 
751  static unsigned long coroutineMicros() {
752  return T_CLOCK::micros();
753  }
754 
761  static unsigned long coroutineSeconds() {
762  return T_CLOCK::seconds();
763  }
764 
765  private:
766  // Disable copy-constructor and assignment operator
767  CoroutineTemplate(const CoroutineTemplate&) = delete;
768  CoroutineTemplate& operator=(const CoroutineTemplate&) = delete;
769 
776  void insertAtRoot() {
777  CoroutineTemplate** root = getRoot();
778  mNext = *root;
779  *root = this;
780  }
781 
782  protected:
785 
787  void* mJumpPoint = nullptr;
788 
793  const void* mName = nullptr;
794 
797 
800 
806  T_DELAY mDelayStart;
807 
813  T_DELAY mDelayDuration;
814 
817 };
818 
826 
827 }
828 
829 #endif
ace_routine::CoroutineTemplate::printNameTo
void printNameTo(Print &printer, uint8_t maxLen=0) const
Print name to the given Printer.
Definition: Coroutine.h:389
ace_routine::CoroutineTemplate::kNameTypeFString
static const uint8_t kNameTypeFString
Coroutine name is a const __FlashStringHelper* f-string.
Definition: Coroutine.h:302
ace_routine::CoroutineProfiler::updateElapsedMicros
virtual void updateElapsedMicros(uint32_t micros)=0
Process the completion of the runCoroutine() method which took micros microseconds.
ace_routine::CoroutineTemplate::mNext
CoroutineTemplate * mNext
Pointer to the next coroutine in a singly-linked list.
Definition: Coroutine.h:784
ace_routine::CoroutineTemplate::getStatus
Status getStatus() const
Return the status of the coroutine.
Definition: Coroutine.h:648
ace_routine::CoroutineTemplate::isDelaying
bool isDelaying() const
The coroutine returned using COROUTINE_DELAY().
Definition: Coroutine.h:500
ace_routine::CoroutineTemplate::setEnding
void setEnding()
Set the kStatusEnding state.
Definition: Coroutine.h:678
ace_routine::CoroutineTemplate::getJump
void * getJump() const
Pointer to label where execute will start on the next call to runCoroutine().
Definition: Coroutine.h:666
ace_routine::CoroutineTemplate::kStatusYielding
static const Status kStatusYielding
Coroutine returned using the COROUTINE_YIELD() statement.
Definition: Coroutine.h:614
ace_routine::CoroutineTemplate::isDone
bool isDone() const
The coroutine is either Ending or Terminated.
Definition: Coroutine.h:525
ace_routine::CoroutineTemplate::getCName
const char * getCName() const
Get name of the coroutine assuming it's a c-string.
Definition: Coroutine.h:375
ace_routine::CoroutineTemplate::setName
void setName(const char *name)
Set the name of the coroutine to the given c-string.
Definition: Coroutine.h:363
ace_routine::CoroutineTemplate::getNameType
uint8_t getNameType() const
Return the type of the name string, either kNameTypeCString or kNameTypeFString.
Definition: Coroutine.h:360
ace_routine::CoroutineTemplate::isYielding
bool isYielding() const
The coroutine returned using COROUTINE_YIELD().
Definition: Coroutine.h:497
ace_routine::CoroutineTemplate::setDelayMicros
void setDelayMicros(T_DELAY delayMicros)
Configure the delay timer for delayMicros.
Definition: Coroutine.h:713
ace_routine::CoroutineTemplate::~CoroutineTemplate
~CoroutineTemplate()=default
Destructor.
ace_routine::CoroutineTemplate::getNext
CoroutineTemplate ** getNext()
Return the next pointer as a pointer to the pointer, similar to getRoot().
Definition: Coroutine.h:570
ace_routine::CoroutineTemplate::setYielding
void setYielding()
Set the kStatusDelaying state.
Definition: Coroutine.h:672
ace_routine::CoroutineTemplate::setJump
void setJump(void *jumpPoint)
Pointer to label where execute will start on the next call to runCoroutine().
Definition: Coroutine.h:660
ace_routine::CoroutineTemplate::getRoot
static CoroutineTemplate ** getRoot()
Get the pointer to the root pointer.
Definition: Coroutine.h:557
ace_routine::CoroutineTemplate::CoroutineTemplate
CoroutineTemplate()
Constructor.
Definition: Coroutine.h:629
ace_routine::CoroutineTemplate::mNameType
uint8_t mNameType
String type of the coroutine mName.
Definition: Coroutine.h:796
ace_routine::CoroutineTemplate::kNameTypeCString
static const uint8_t kNameTypeCString
Coroutine name is a const char* c-string.
Definition: Coroutine.h:299
ace_routine::CoroutineTemplate::getProfiler
CoroutineProfiler * getProfiler() const
Get the profiler.
Definition: Coroutine.h:550
ace_routine::CoroutineTemplate::suspend
void suspend()
Suspend the coroutine at the next scheduler iteration.
Definition: Coroutine.h:432
ace_routine::CoroutineTemplate::runCoroutine
virtual int runCoroutine()=0
The body of the coroutine.
ace_routine::CoroutineTemplate
Base class of all coroutines.
Definition: Coroutine.h:292
ace_routine::CoroutineTemplate::setupCoroutine
void setupCoroutine(const char *) ACE_ROUTINE_DEPRECATED
Deprecated method that does nothing.
Definition: Coroutine.h:535
ace_routine::CoroutineTemplate::coroutineMillis
static unsigned long coroutineMillis()
Returns the current millisecond clock.
Definition: Coroutine.h:742
ace_routine::CoroutineTemplate::setProfiler
void setProfiler(CoroutineProfiler *profiler)
Set the profiler.
Definition: Coroutine.h:547
ace_routine::CoroutineTemplate::mStatus
Status mStatus
Run-state of the coroutine.
Definition: Coroutine.h:799
ace_routine::CoroutineTemplate::setName
void setName(const __FlashStringHelper *name)
Set the name of the coroutine to the given f-string.
Definition: Coroutine.h:369
compat.h
ace_routine::CoroutineTemplate::isDelayMicrosExpired
bool isDelayMicrosExpired() const
Check if delay micros time is over.
Definition: Coroutine.h:480
ace_routine::CoroutineProfiler
An interface class for profiling classes that can track the elapsed time consumed by Coroutine::runCo...
Definition: CoroutineProfiler.h:36
ace_routine::CoroutineTemplate::setDelaying
void setDelaying()
Set the kStatusDelaying state.
Definition: Coroutine.h:675
ace_routine::CoroutineTemplate::mName
const void * mName
Name of the coroutine, either (const char*) or (const __FlashStringHelper*).
Definition: Coroutine.h:793
ace_routine::CoroutineTemplate::setDelayMillis
void setDelayMillis(T_DELAY delayMillis)
Configure the delay timer for delayMillis.
Definition: Coroutine.h:699
ace_routine::CoroutineTemplate::isDelaySecondsExpired
bool isDelaySecondsExpired() const
Check if delay seconds time is over.
Definition: Coroutine.h:487
ace_routine::CoroutineTemplate::resume
void resume()
Add a Suspended coroutine into the head of the scheduler linked list, and change the state to Yieldin...
Definition: Coroutine.h:443
ace_routine::CoroutineTemplate::kStatusSuspended
static const Status kStatusSuspended
Coroutine has been suspended using suspend() and the scheduler should remove it from the queue upon t...
Definition: Coroutine.h:611
ace_routine::CoroutineTemplate::Status
uint8_t Status
The execution status of the coroutine, corresponding to the COROUTINE_YIELD(), COROUTINE_DELAY(),...
Definition: Coroutine.h:603
ace_routine::CoroutineTemplate::setRunning
void setRunning()
Set the kStatusRunning state.
Definition: Coroutine.h:669
ace_routine::CoroutineTemplate::kStatusEnding
static const Status kStatusEnding
Coroutine executed the COROUTINE_END() statement.
Definition: Coroutine.h:623
ace_routine::CoroutineTemplate::coroutineSeconds
static unsigned long coroutineSeconds()
Returns the current clock in unit of seconds, truncated to the lower 16-bits.
Definition: Coroutine.h:761
ace_routine::CoroutineTemplate::reset
void reset()
Reset the coroutine to its initial state.
Definition: Coroutine.h:467
ace_routine::CoroutineTemplate::kStatusTerminated
static const Status kStatusTerminated
Coroutine has ended and no longer in the scheduler queue.
Definition: Coroutine.h:626
ace_routine::CoroutineTemplate::isRunning
bool isRunning() const
The coroutine is currently running.
Definition: Coroutine.h:503
ace_routine::CoroutineTemplate::mDelayStart
T_DELAY mDelayStart
Start time provided by COROUTINE_DELAY(), COROUTINE_DELAY_MICROS(), or COROUTINE_DELAY_SECONDS().
Definition: Coroutine.h:806
ace_routine::CoroutineTemplate::getFName
const __FlashStringHelper * getFName() const
Get name of the coroutine assuming it's an f-string.
Definition: Coroutine.h:378
ace_routine::CoroutineTemplate::runCoroutineWithProfiler
int runCoroutineWithProfiler()
This is a variant of runCoroutine() which measures the execution time of runCoroutine() and updates t...
Definition: Coroutine.h:344
ace_routine::CoroutineTemplate::setDelaySeconds
void setDelaySeconds(T_DELAY delaySeconds)
Configure the delay timer for delaySeconds.
Definition: Coroutine.h:727
ace_routine::CoroutineTemplate::setupCoroutine
virtual void setupCoroutine()
Perform coroutine initialization.
Definition: Coroutine.h:331
ace_routine::CoroutineTemplate::isDelayExpired
bool isDelayExpired() const
Check if delay millis time is over.
Definition: Coroutine.h:473
ace_routine::CoroutineTemplate::coroutineMicros
static unsigned long coroutineMicros()
Returns the current microseconds clock.
Definition: Coroutine.h:751
ace_routine::CoroutineSchedulerTemplate
Class that manages instances of the Coroutine class, and executes them in a round-robin fashion.
Definition: Coroutine.h:274
ace_routine::CoroutineTemplate::mDelayDuration
T_DELAY mDelayDuration
Delay time specified by COROUTINE_DELAY(), COROUTINE_DELAY_MICROS() or, COROUTINE_DELAY_SECONDS().
Definition: Coroutine.h:813
ace_routine::CoroutineTemplate::mProfiler
CoroutineProfiler * mProfiler
Pointer to a profiler instance, either static or on the heap.
Definition: Coroutine.h:816
ace_routine::CoroutineTemplate::setTerminated
void setTerminated()
Set status to indicate that the Coroutine has been removed from the Scheduler queue.
Definition: Coroutine.h:684
ace_routine::CoroutineTemplate::isSuspended
bool isSuspended() const
The coroutine was suspended with a call to suspend().
Definition: Coroutine.h:494
ace_routine::CoroutineTemplate::isTerminated
bool isTerminated() const
The coroutine was terminated by the scheduler with a call to setTerminated().
Definition: Coroutine.h:518
ace_routine::CoroutineTemplate::isEnding
bool isEnding() const
The coroutine returned using COROUTINE_END().
Definition: Coroutine.h:510
ace_routine::CoroutineTemplate::mJumpPoint
void * mJumpPoint
Address of the label used by the computed-goto.
Definition: Coroutine.h:787
ace_routine::CoroutineTemplate::setupCoroutine
void setupCoroutine(const __FlashStringHelper *) ACE_ROUTINE_DEPRECATED
Deprecated method that does nothing.
Definition: Coroutine.h:543
ACE_ROUTINE_DEPRECATED
#define ACE_ROUTINE_DEPRECATED
Macro that indicates a deprecation.
Definition: Coroutine.h:65
ace_routine::CoroutineTemplate::kStatusDelaying
static const Status kStatusDelaying
Coroutine returned using the COROUTINE_DELAY() statement.
Definition: Coroutine.h:617
ace_routine::CoroutineTemplate::statusPrintTo
void statusPrintTo(Print &printer)
Print the human-readable string of the Status.
Definition: Coroutine.h:651
ace_routine::CoroutineTemplate::kStatusRunning
static const Status kStatusRunning
Coroutine is currenly running.
Definition: Coroutine.h:620