TaskSchedulerDeclarations.h 14 KB

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