TaskSchedulerDeclarations.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // Cooperative multitasking library for Arduino
  2. // Copyright (c) 2015-2019 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 runs 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 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 callbacks via inheritance
  23. // #define _TASK_DEFINE_MILLIS // Force forward declaration of millis() and micros() "C" style
  24. // #define _TASK_EXPOSE_CHAIN // Methods to access tasks in the task chain
  25. class Scheduler;
  26. #ifdef _TASK_DEBUG
  27. #define _TASK_SCOPE public
  28. #else
  29. #define _TASK_SCOPE private
  30. #endif
  31. #define TASK_IMMEDIATE 0
  32. #define TASK_FOREVER (-1)
  33. #define TASK_ONCE 1
  34. #ifdef _TASK_TIMEOUT
  35. #define TASK_NOTIMEOUT 0
  36. #endif
  37. #ifdef _TASK_PRIORITY
  38. extern Scheduler* iCurrentScheduler;
  39. #endif // _TASK_PRIORITY
  40. #ifdef _TASK_INLINE
  41. #define INLINE inline
  42. #else
  43. #define INLINE
  44. #endif
  45. #ifndef _TASK_MICRO_RES
  46. #define TASK_MILLISECOND 1UL
  47. #define TASK_SECOND 1000UL
  48. #define TASK_MINUTE 60000UL
  49. #define TASK_HOUR 3600000UL
  50. #else
  51. #define TASK_MILLISECOND 1000UL
  52. #define TASK_SECOND 1000000UL
  53. #define TASK_MINUTE 60000000UL
  54. #define TASK_HOUR 3600000000UL
  55. #endif // _TASK_MICRO_RES
  56. #ifdef _TASK_STATUS_REQUEST
  57. #define _TASK_SR_NODELAY 1
  58. #define _TASK_SR_DELAY 2
  59. class StatusRequest {
  60. public:
  61. INLINE StatusRequest();
  62. INLINE void setWaiting(unsigned int aCount = 1);
  63. INLINE bool signal(int aStatus = 0);
  64. INLINE void signalComplete(int aStatus = 0);
  65. INLINE bool pending();
  66. INLINE bool completed();
  67. INLINE int getStatus();
  68. INLINE int getCount();
  69. _TASK_SCOPE:
  70. unsigned int iCount; // number of statuses to wait for. waiting for more that 65000 events seems unreasonable: unsigned int should be sufficient
  71. int iStatus; // status of the last completed request. negative = error; zero = OK; positive = OK with a specific status
  72. };
  73. #endif // _TASK_STATUS_REQUEST
  74. #ifdef _TASK_STD_FUNCTION
  75. #include <functional>
  76. typedef std::function<void()> TaskCallback;
  77. typedef std::function<void()> TaskOnDisable;
  78. typedef std::function<bool()> TaskOnEnable;
  79. #else
  80. typedef void (*TaskCallback)();
  81. typedef void (*TaskOnDisable)();
  82. typedef bool (*TaskOnEnable)();
  83. #endif // _TASK_STD_FUNCTION
  84. #ifdef _TASK_SLEEP_ON_IDLE_RUN
  85. typedef void (*SleepCallback)( unsigned long aDuration );
  86. extern Scheduler* iSleepScheduler;
  87. extern SleepCallback iSleepMethod;
  88. #endif // _TASK_SLEEP_ON_IDLE_RUN
  89. typedef struct {
  90. bool enabled : 1; // indicates that task is enabled or not.
  91. bool inonenable : 1; // indicates that task execution is inside OnEnable method (preventing infinite loops)
  92. #ifdef _TASK_STATUS_REQUEST
  93. uint8_t waiting : 2; // indication if task is waiting on the status request
  94. #endif
  95. #ifdef _TASK_TIMEOUT
  96. bool timeout : 1; // indication if task is waiting on the status request
  97. #endif
  98. } __task_status;
  99. class Scheduler;
  100. class Task {
  101. friend class Scheduler;
  102. public:
  103. #ifdef _TASK_OO_CALLBACKS
  104. INLINE Task(unsigned long aInterval=0, long aIterations=0, Scheduler* aScheduler=NULL, bool aEnable=false);
  105. #else
  106. INLINE Task(unsigned long aInterval=0, long aIterations=0, TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, bool aEnable=false, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  107. #endif // _TASK_OO_CALLBACKS
  108. #ifdef _TASK_STATUS_REQUEST
  109. #ifdef _TASK_OO_CALLBACKS
  110. // INLINE Task(Scheduler* aScheduler=NULL);
  111. INLINE Task(Scheduler* aScheduler);
  112. #else
  113. // INLINE Task(TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  114. INLINE Task(TaskCallback aCallback, Scheduler* aScheduler, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  115. #endif // _TASK_OO_CALLBACKS
  116. #endif // _TASK_STATUS_REQUEST
  117. virtual INLINE ~Task();
  118. #ifdef _TASK_TIMEOUT
  119. INLINE void setTimeout(unsigned long aTimeout, bool aReset=false);
  120. INLINE void resetTimeout();
  121. INLINE unsigned long getTimeout();
  122. INLINE long untilTimeout();
  123. INLINE bool timedOut();
  124. #endif
  125. INLINE void enable();
  126. INLINE bool enableIfNot();
  127. INLINE void enableDelayed(unsigned long aDelay=0);
  128. INLINE void restart();
  129. INLINE void restartDelayed(unsigned long aDelay=0);
  130. INLINE void delay(unsigned long aDelay=0);
  131. INLINE void forceNextIteration();
  132. INLINE bool disable();
  133. INLINE bool isEnabled();
  134. #ifdef _TASK_OO_CALLBACKS
  135. INLINE void set(unsigned long aInterval, long aIterations);
  136. #else
  137. INLINE void set(unsigned long aInterval, long aIterations, TaskCallback aCallback,TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  138. #endif // _TASK_OO_CALLBACKS
  139. INLINE void setInterval(unsigned long aInterval);
  140. INLINE unsigned long getInterval();
  141. INLINE void setIterations(long aIterations);
  142. INLINE long getIterations();
  143. INLINE unsigned long getRunCounter() ;
  144. #ifdef _TASK_OO_CALLBACKS
  145. virtual INLINE bool Callback() =0; // return true if run was "productive - this will disable sleep on the idle run for next pass
  146. virtual INLINE bool OnEnable(); // return true if task should be enabled, false if it should remain disabled
  147. virtual INLINE void OnDisable();
  148. #else
  149. INLINE void setCallback(TaskCallback aCallback) ;
  150. INLINE void setOnEnable(TaskOnEnable aCallback) ;
  151. INLINE void setOnDisable(TaskOnDisable aCallback) ;
  152. INLINE void yield(TaskCallback aCallback);
  153. INLINE void yieldOnce(TaskCallback aCallback);
  154. #endif // _TASK_OO_CALLBACKS
  155. INLINE bool isFirstIteration() ;
  156. INLINE bool isLastIteration() ;
  157. #ifdef _TASK_TIMECRITICAL
  158. INLINE long getOverrun() ;
  159. INLINE long getStartDelay() ;
  160. #endif // _TASK_TIMECRITICAL
  161. #ifdef _TASK_STATUS_REQUEST
  162. INLINE void waitFor(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
  163. INLINE void waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
  164. INLINE StatusRequest* getStatusRequest() ;
  165. INLINE StatusRequest* getInternalStatusRequest() ;
  166. #endif // _TASK_STATUS_REQUEST
  167. #ifdef _TASK_WDT_IDS
  168. INLINE void setId(unsigned int aID) ;
  169. INLINE unsigned int getId() ;
  170. INLINE void setControlPoint(unsigned int aPoint) ;
  171. INLINE unsigned int getControlPoint() ;
  172. #endif // _TASK_WDT_IDS
  173. #ifdef _TASK_LTS_POINTER
  174. INLINE void setLtsPointer(void *aPtr) ;
  175. INLINE void* getLtsPointer() ;
  176. #endif // _TASK_LTS_POINTER
  177. #ifdef _TASK_EXPOSE_CHAIN
  178. INLINE Task* getPreviousTask() { return iPrev; }; // pointer to the previous task in the chain, NULL if first or not set
  179. INLINE Task* getNextTask() { return iNext; }; // pointer to the next task in the chain, NULL if last or not set
  180. #endif // _TASK_EXPOSE_CHAIN
  181. _TASK_SCOPE:
  182. INLINE void reset();
  183. volatile __task_status iStatus;
  184. volatile unsigned long iInterval; // execution interval in milliseconds (or microseconds). 0 - immediate
  185. volatile unsigned long iDelay; // actual delay until next execution (usually equal iInterval)
  186. volatile unsigned long iPreviousMillis; // previous invocation time (millis). Next invocation = iPreviousMillis + iInterval. Delayed tasks will "catch up"
  187. #ifdef _TASK_TIMECRITICAL
  188. volatile long iOverrun; // negative if task is "catching up" to it's schedule (next invocation time is already in the past)
  189. volatile long iStartDelay; // actual execution of the task's callback method was delayed by this number of millis
  190. #endif // _TASK_TIMECRITICAL
  191. volatile long iIterations; // number of iterations left. 0 - last iteration. -1 - infinite iterations
  192. long iSetIterations; // number of iterations originally requested (for restarts)
  193. unsigned long iRunCounter; // current number of iteration (starting with 1). Resets on enable.
  194. #ifndef _TASK_OO_CALLBACKS
  195. TaskCallback iCallback; // pointer to the void callback method
  196. TaskOnEnable iOnEnable; // pointer to the bool OnEnable callback method
  197. TaskOnDisable iOnDisable; // pointer to the void OnDisable method
  198. #endif // _TASK_OO_CALLBACKS
  199. Task *iPrev, *iNext; // pointers to the previous and next tasks in the chain
  200. Scheduler *iScheduler; // pointer to the current scheduler
  201. #ifdef _TASK_STATUS_REQUEST
  202. StatusRequest *iStatusRequest; // pointer to the status request task is or was waiting on
  203. StatusRequest iMyStatusRequest; // internal Status request to let other tasks know of completion
  204. #endif // _TASK_STATUS_REQUEST
  205. #ifdef _TASK_WDT_IDS
  206. unsigned int iTaskID; // task ID (for debugging and watchdog identification)
  207. unsigned int iControlPoint; // current control point within the callback method. Reset to 0 by scheduler at the beginning of each pass
  208. #endif // _TASK_WDT_IDS
  209. #ifdef _TASK_LTS_POINTER
  210. void *iLTS; // pointer to task's local storage. Needs to be recast to appropriate type (usually a struct).
  211. #endif // _TASK_LTS_POINTER
  212. #ifdef _TASK_TIMEOUT
  213. unsigned long iTimeout; // Task overall timeout
  214. unsigned long iStarttime; // millis at task start time
  215. #endif // _TASK_TIMEOUT
  216. };
  217. class Scheduler {
  218. friend class Task;
  219. public:
  220. INLINE Scheduler();
  221. // ~Scheduler();
  222. INLINE void init();
  223. INLINE void addTask(Task& aTask);
  224. INLINE void deleteTask(Task& aTask);
  225. #ifdef _TASK_PRIORITY
  226. INLINE void disableAll(bool aRecursive = true);
  227. INLINE void enableAll(bool aRecursive = true);
  228. INLINE void startNow(bool aRecursive = true); // reset ALL active tasks to immediate execution NOW.
  229. #else
  230. INLINE void disableAll();
  231. INLINE void enableAll();
  232. INLINE void startNow(); // reset ALL active tasks to immediate execution NOW.
  233. #endif
  234. INLINE bool execute(); // Returns true if none of the tasks' callback methods was invoked (true = idle run)
  235. INLINE Task& currentTask() ; // DEPRICATED
  236. INLINE Task* getCurrentTask() ; // Returns pointer to the currently active task
  237. INLINE long timeUntilNextIteration(Task& aTask); // return number of ms until next iteration of a given Task
  238. #ifdef _TASK_SLEEP_ON_IDLE_RUN
  239. INLINE void allowSleep(bool aState = true);
  240. INLINE void setSleepMethod( SleepCallback aCallback );
  241. #endif // _TASK_SLEEP_ON_IDLE_RUN
  242. #ifdef _TASK_LTS_POINTER
  243. INLINE void* currentLts();
  244. #endif // _TASK_LTS_POINTER
  245. #ifdef _TASK_TIMECRITICAL
  246. INLINE bool isOverrun();
  247. INLINE void cpuLoadReset();
  248. INLINE unsigned long getCpuLoadCycle(){ return iCPUCycle; };
  249. INLINE unsigned long getCpuLoadIdle() { return iCPUIdle; };
  250. INLINE unsigned long getCpuLoadTotal();
  251. #endif // _TASK_TIMECRITICAL
  252. #ifdef _TASK_PRIORITY
  253. INLINE void setHighPriorityScheduler(Scheduler* aScheduler);
  254. INLINE static Scheduler& currentScheduler() { return *(iCurrentScheduler); };
  255. #endif // _TASK_PRIORITY
  256. #ifdef _TASK_EXPOSE_CHAIN
  257. INLINE Task* getFirstTask() { return iFirst; }; // pointer to the previous task in the chain, NULL if first or not set
  258. INLINE Task* getLastTask() { return iLast; }; // pointer to the next task in the chain, NULL if last or not set
  259. #endif // _TASK_EXPOSE_CHAIN
  260. _TASK_SCOPE:
  261. Task *iFirst, *iLast, *iCurrent; // pointers to first, last and current tasks in the chain
  262. #ifdef _TASK_SLEEP_ON_IDLE_RUN
  263. bool iAllowSleep; // indication if putting MC to IDLE_SLEEP mode is allowed by the program at this time.
  264. #endif // _TASK_SLEEP_ON_IDLE_RUN
  265. #ifdef _TASK_PRIORITY
  266. Scheduler *iHighPriority; // Pointer to a higher priority scheduler
  267. #endif // _TASK_PRIORITY
  268. #ifdef _TASK_TIMECRITICAL
  269. unsigned long iCPUStart;
  270. unsigned long iCPUCycle;
  271. unsigned long iCPUIdle;
  272. #endif // _TASK_TIMECRITICAL
  273. };
  274. #endif /* _TASKSCHEDULERDECLARATIONS_H_ */