TaskSchedulerDeclarations.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Cooperative multitasking library for Arduino
  2. // Copyright (c) 2015-2017 Anatoli Arkhipenko
  3. #include <stddef.h>
  4. #include <stdint.h>
  5. #ifndef _TASKSCHEDULERDECLARATIONS_H_
  6. #define _TASKSCHEDULERDECLARATIONS_H_
  7. // ----------------------------------------
  8. // The following "defines" control library functionality at compile time,
  9. // and should be used in the main sketch depending on the functionality required
  10. //
  11. // #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
  12. // #define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between tasks if no callback methods were invoked during the pass
  13. // #define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
  14. // #define _TASK_WDT_IDS // Compile with support for wdt control points and task ids
  15. // #define _TASK_LTS_POINTER // Compile with support for local task storage pointer
  16. // #define _TASK_PRIORITY // Support for layered scheduling priority
  17. // #define _TASK_MICRO_RES // Support for microsecond resolution
  18. // #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 and ESP32 ONLY)
  19. // #define _TASK_DEBUG // Make all methods and variables public for debug purposes
  20. // #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
  21. // #define _TASK_TIMEOUT // Support for overall task timeout
  22. // #define _TASK_OO_CALLBACKS // Support for dynamic callback method binding
  23. #ifdef _TASK_DEBUG
  24. #define _TASK_SCOPE public
  25. #else
  26. #define _TASK_SCOPE private
  27. #endif
  28. #define TASK_IMMEDIATE 0
  29. #define TASK_FOREVER (-1)
  30. #define TASK_ONCE 1
  31. #ifdef _TASK_TIMEOUT
  32. #define TASK_NOTIMEOUT 0
  33. #endif
  34. #ifdef _TASK_PRIORITY
  35. class Scheduler;
  36. extern Scheduler* iCurrentScheduler;
  37. #endif // _TASK_PRIORITY
  38. #if !defined(ARDUINO)
  39. extern unsigned long micros(void);
  40. extern unsigned long millis(void);
  41. #endif
  42. #ifdef _TASK_INLINE
  43. #define INLINE inline
  44. #else
  45. #define INLINE
  46. #endif
  47. #ifndef _TASK_MICRO_RES
  48. #define TASK_MILLISECOND 1UL
  49. #define TASK_SECOND 1000UL
  50. #define TASK_MINUTE 60000UL
  51. #define TASK_HOUR 3600000UL
  52. #else
  53. #define TASK_MILLISECOND 1000UL
  54. #define TASK_SECOND 1000000UL
  55. #define TASK_MINUTE 60000000UL
  56. #define TASK_HOUR 3600000000UL
  57. #endif // _TASK_MICRO_RES
  58. #ifdef _TASK_STATUS_REQUEST
  59. #define _TASK_SR_NODELAY 1
  60. #define _TASK_SR_DELAY 2
  61. class StatusRequest {
  62. public:
  63. INLINE StatusRequest();
  64. INLINE void setWaiting(unsigned int aCount = 1);
  65. INLINE bool signal(int aStatus = 0);
  66. INLINE void signalComplete(int aStatus = 0);
  67. INLINE bool pending();
  68. INLINE bool completed();
  69. INLINE int getStatus();
  70. INLINE int getCount();
  71. _TASK_SCOPE:
  72. unsigned int iCount; // number of statuses to wait for. waiting for more that 65000 events seems unreasonable: unsigned int should be sufficient
  73. int iStatus; // status of the last completed request. negative = error; zero = OK; positive = OK with a specific status
  74. };
  75. #endif // _TASK_STATUS_REQUEST
  76. #ifdef _TASK_STD_FUNCTION
  77. #include <functional>
  78. typedef std::function<void()> TaskCallback;
  79. typedef std::function<void()> TaskOnDisable;
  80. typedef std::function<bool()> TaskOnEnable;
  81. #else
  82. typedef void (*TaskCallback)();
  83. typedef void (*TaskOnDisable)();
  84. typedef bool (*TaskOnEnable)();
  85. #endif
  86. typedef struct {
  87. bool enabled : 1; // indicates that task is enabled or not.
  88. bool inonenable : 1; // indicates that task execution is inside OnEnable method (preventing infinite loops)
  89. #ifdef _TASK_STATUS_REQUEST
  90. uint8_t waiting : 2; // indication if task is waiting on the status request
  91. #endif
  92. #ifdef _TASK_TIMEOUT
  93. bool timeout : 1; // indication if task is waiting on the status request
  94. #endif
  95. } __task_status;
  96. class Scheduler;
  97. class Task {
  98. friend class Scheduler;
  99. public:
  100. #ifdef _TASK_OO_CALLBACKS
  101. INLINE Task(unsigned long aInterval=0, long aIterations=0, Scheduler* aScheduler=NULL, bool aEnable=false);
  102. #else
  103. INLINE Task(unsigned long aInterval=0, long aIterations=0, TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, bool aEnable=false, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  104. #endif // _TASK_OO_CALLBACKS
  105. #ifdef _TASK_STATUS_REQUEST
  106. #ifdef _TASK_OO_CALLBACKS
  107. INLINE Task(Scheduler* aScheduler=NULL);
  108. #else
  109. INLINE Task(TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  110. #endif // _TASK_OO_CALLBACKS
  111. #endif // _TASK_STATUS_REQUEST
  112. INLINE ~Task();
  113. #ifdef _TASK_TIMEOUT
  114. INLINE void setTimeout(unsigned long aTimeout, bool aReset=false);
  115. INLINE void resetTimeout();
  116. INLINE unsigned long getTimeout();
  117. INLINE long untilTimeout();
  118. INLINE bool timedOut();
  119. #endif
  120. INLINE void enable();
  121. INLINE bool enableIfNot();
  122. INLINE void enableDelayed(unsigned long aDelay=0);
  123. INLINE void restart();
  124. INLINE void restartDelayed(unsigned long aDelay=0);
  125. INLINE void delay(unsigned long aDelay=0);
  126. INLINE void forceNextIteration();
  127. INLINE bool disable();
  128. INLINE bool isEnabled();
  129. #ifdef _TASK_OO_CALLBACKS
  130. INLINE void set(unsigned long aInterval, long aIterations);
  131. #else
  132. INLINE void set(unsigned long aInterval, long aIterations, TaskCallback aCallback,TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  133. #endif // _TASK_OO_CALLBACKS
  134. INLINE void setInterval(unsigned long aInterval);
  135. INLINE unsigned long getInterval();
  136. INLINE void setIterations(long aIterations);
  137. INLINE long getIterations();
  138. INLINE unsigned long getRunCounter() ;
  139. #ifdef _TASK_OO_CALLBACKS
  140. virtual INLINE bool Callback() =0; // return true if run was "productive - this will disable sleep on the idle run for next pass
  141. virtual INLINE bool OnEnable(); // return true if task should be enabled, false if it should remain disabled
  142. virtual INLINE void OnDisable();
  143. #else
  144. INLINE void setCallback(TaskCallback aCallback) ;
  145. INLINE void setOnEnable(TaskOnEnable aCallback) ;
  146. INLINE void setOnDisable(TaskOnDisable aCallback) ;
  147. INLINE void yield(TaskCallback aCallback);
  148. INLINE void yieldOnce(TaskCallback aCallback);
  149. #endif // _TASK_OO_CALLBACKS
  150. INLINE bool isFirstIteration() ;
  151. INLINE bool isLastIteration() ;
  152. #ifdef _TASK_TIMECRITICAL
  153. INLINE long getOverrun() ;
  154. INLINE long getStartDelay() ;
  155. #endif // _TASK_TIMECRITICAL
  156. #ifdef _TASK_STATUS_REQUEST
  157. INLINE void waitFor(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
  158. INLINE void waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
  159. INLINE StatusRequest* getStatusRequest() ;
  160. INLINE StatusRequest* getInternalStatusRequest() ;
  161. #endif // _TASK_STATUS_REQUEST
  162. #ifdef _TASK_WDT_IDS
  163. INLINE void setId(unsigned int aID) ;
  164. INLINE unsigned int getId() ;
  165. INLINE void setControlPoint(unsigned int aPoint) ;
  166. INLINE unsigned int getControlPoint() ;
  167. #endif // _TASK_WDT_IDS
  168. #ifdef _TASK_LTS_POINTER
  169. INLINE void setLtsPointer(void *aPtr) ;
  170. void* getLtsPointer() ;
  171. #endif // _TASK_LTS_POINTER
  172. _TASK_SCOPE:
  173. INLINE void reset();
  174. volatile __task_status iStatus;
  175. volatile unsigned long iInterval; // execution interval in milliseconds (or microseconds). 0 - immediate
  176. volatile unsigned long iDelay; // actual delay until next execution (usually equal iInterval)
  177. volatile unsigned long iPreviousMillis; // previous invocation time (millis). Next invocation = iPreviousMillis + iInterval. Delayed tasks will "catch up"
  178. #ifdef _TASK_TIMECRITICAL
  179. volatile long iOverrun; // negative if task is "catching up" to it's schedule (next invocation time is already in the past)
  180. volatile long iStartDelay; // actual execution of the task's callback method was delayed by this number of millis
  181. #endif // _TASK_TIMECRITICAL
  182. volatile long iIterations; // number of iterations left. 0 - last iteration. -1 - infinite iterations
  183. long iSetIterations; // number of iterations originally requested (for restarts)
  184. unsigned long iRunCounter; // current number of iteration (starting with 1). Resets on enable.
  185. #ifndef _TASK_OO_CALLBACKS
  186. TaskCallback iCallback; // pointer to the void callback method
  187. TaskOnEnable iOnEnable; // pointer to the bolol OnEnable callback method
  188. TaskOnDisable iOnDisable; // pointer to the void OnDisable method
  189. #endif // _TASK_OO_CALLBACKS
  190. Task *iPrev, *iNext; // pointers to the previous and next tasks in the chain
  191. Scheduler *iScheduler; // pointer to the current scheduler
  192. #ifdef _TASK_STATUS_REQUEST
  193. StatusRequest *iStatusRequest; // pointer to the status request task is or was waiting on
  194. StatusRequest iMyStatusRequest; // internal Status request to let other tasks know of completion
  195. #endif // _TASK_STATUS_REQUEST
  196. #ifdef _TASK_WDT_IDS
  197. unsigned int iTaskID; // task ID (for debugging and watchdog identification)
  198. unsigned int iControlPoint; // current control point within the callback method. Reset to 0 by scheduler at the beginning of each pass
  199. #endif // _TASK_WDT_IDS
  200. #ifdef _TASK_LTS_POINTER
  201. void *iLTS; // pointer to task's local storage. Needs to be recast to appropriate type (usually a struct).
  202. #endif // _TASK_LTS_POINTER
  203. #ifdef _TASK_TIMEOUT
  204. unsigned long iTimeout; // Task overall timeout
  205. unsigned long iStarttime; // millis at task start time
  206. #endif // _TASK_TIMEOUT
  207. };
  208. class Scheduler {
  209. friend class Task;
  210. public:
  211. INLINE Scheduler();
  212. // ~Scheduler();
  213. INLINE void init();
  214. INLINE void addTask(Task& aTask);
  215. INLINE void deleteTask(Task& aTask);
  216. INLINE void disableAll(bool aRecursive = true);
  217. INLINE void enableAll(bool aRecursive = true);
  218. INLINE bool execute(); // Returns true if none of the tasks' callback methods was invoked (true = idle run)
  219. INLINE void startNow(bool aRecursive = true); // reset ALL active tasks to immediate execution NOW.
  220. INLINE Task& currentTask() ;
  221. INLINE long timeUntilNextIteration(Task& aTask); // return number of ms until next iteration of a given Task
  222. #ifdef _TASK_SLEEP_ON_IDLE_RUN
  223. INLINE void allowSleep(bool aState = true);
  224. #endif // _TASK_SLEEP_ON_IDLE_RUN
  225. #ifdef _TASK_LTS_POINTER
  226. INLINE void* currentLts();
  227. #endif // _TASK_LTS_POINTER
  228. #ifdef _TASK_TIMECRITICAL
  229. INLINE bool isOverrun();
  230. #endif // _TASK_TIMECRITICAL
  231. #ifdef _TASK_PRIORITY
  232. INLINE void setHighPriorityScheduler(Scheduler* aScheduler);
  233. INLINE static Scheduler& currentScheduler() { return *(iCurrentScheduler); };
  234. #endif // _TASK_PRIORITY
  235. _TASK_SCOPE:
  236. Task *iFirst, *iLast, *iCurrent; // pointers to first, last and current tasks in the chain
  237. #ifdef _TASK_SLEEP_ON_IDLE_RUN
  238. bool iAllowSleep; // indication if putting avr to IDLE_SLEEP mode is allowed by the program at this time.
  239. #endif // _TASK_SLEEP_ON_IDLE_RUN
  240. #ifdef _TASK_PRIORITY
  241. Scheduler *iHighPriority; // Pointer to a higher priority scheduler
  242. #endif // _TASK_PRIORITY
  243. };
  244. #endif /* _TASKSCHEDULERDECLARATIONS_H_ */