TaskSchedulerDeclarations.h 121 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135
  1. /**
  2. * @file TaskSchedulerDeclarations.h
  3. * @brief Cooperative multitasking library for Arduino microcontrollers
  4. * @author Anatoli Arkhipenko
  5. * @version 4.0.0
  6. * @date 2015-2023
  7. * @copyright Copyright (c) 2015-2025 Anatoli Arkhipenko
  8. *
  9. * @details A lightweight implementation of cooperative multitasking (task scheduling) supporting:
  10. * - Periodic task execution, with dynamic execution period in milliseconds (default) or microseconds
  11. * - Number of iterations (limited or infinite number of iterations)
  12. * - Execution of tasks in the predefined sequence
  13. * - Dynamic change of task execution parameters (frequency, number of iterations, callback methods)
  14. * - Power saving via entering IDLE sleep mode when tasks are not scheduled to run
  15. * - Support for event-driven task invocation via Status Request object
  16. * - Support for task IDs and Control Points for error handling and watchdog timer
  17. * - Support for Local Task Storage pointer (allowing the use of same callback code for multiple tasks)
  18. * - Support for layered task prioritization
  19. * - Support for std::functions
  20. * - Overall task timeout
  21. * - Static and dynamic callback method binding
  22. *
  23. * Scheduling overhead: between 15 and 18 microseconds per scheduling pass (Arduino UNO rev 3 @ 16MHz clock, single scheduler w/o prioritization)
  24. */
  25. #ifndef _TASKSCHEDULERDECLARATIONS_H_
  26. #define _TASKSCHEDULERDECLARATIONS_H_
  27. // ----------------------------------------
  28. /**
  29. * @defgroup CompileTimeOptions Compile Time Options
  30. * @brief The following "defines" control library functionality at compile time,
  31. * and should be used in the main sketch depending on the functionality required
  32. * @{
  33. */
  34. /**
  35. * @def _TASK_TIMECRITICAL
  36. * @brief Enable monitoring scheduling overruns
  37. * @details Enables tracking when the current execution took place relative to when it was scheduled.
  38. * Provides getStartDelay() and getOverrun() methods for performance monitoring.
  39. */
  40. /**
  41. * @def _TASK_SLEEP_ON_IDLE_RUN
  42. * @brief Enable 1 ms SLEEP_IDLE powerdowns between runs if no callback methods were invoked during the pass
  43. * @details When enabled, the scheduler will place the processor into IDLE sleep mode for approximately 1 ms
  44. * after what is determined to be an "idle" pass. AVR boards only.
  45. */
  46. /**
  47. * @def _TASK_STATUS_REQUEST
  48. * @brief Compile with support for StatusRequest functionality
  49. * @details Enables triggering tasks on status change events in addition to time-based scheduling.
  50. * Allows tasks to wait on an event and signal event completion to each other.
  51. */
  52. /**
  53. * @def _TASK_WDT_IDS
  54. * @brief Compile with support for watchdog timer control points and task IDs
  55. * @details Each task can be assigned an ID and Control Points can be defined within tasks
  56. * for watchdog timer integration and error handling.
  57. */
  58. /**
  59. * @def _TASK_LTS_POINTER
  60. * @brief Compile with support for local task storage pointer
  61. * @details LTS is a generic (void*) pointer that can reference a variable or structure
  62. * specific to a particular task, allowing the same callback code for multiple tasks.
  63. */
  64. /**
  65. * @def _TASK_PRIORITY
  66. * @brief Support for layered scheduling priority
  67. * @details Enables task prioritization by creating several schedulers and organizing them in priority layers.
  68. * Higher priority tasks are evaluated more frequently.
  69. */
  70. /**
  71. * @def _TASK_MICRO_RES
  72. * @brief Support for microsecond resolution
  73. * @details Enables microsecond scheduling resolution instead of default millisecond resolution.
  74. * All time-relevant parameters will be treated as microseconds.
  75. */
  76. /**
  77. * @def _TASK_STD_FUNCTION
  78. * @brief Support for std::function (ESP8266/ESP32 ONLY)
  79. * @details Enables support for standard functions instead of function pointers for callbacks.
  80. */
  81. /**
  82. * @def _TASK_DEBUG
  83. * @brief Make all methods and variables public for debug purposes
  84. * @details Should not be used in production. Exposes all private and protected members as public.
  85. */
  86. /**
  87. * @def _TASK_INLINE
  88. * @brief Make all methods "inline"
  89. * @details Needed to support some multi-tab, multi-file implementations. Lets compiler optimize.
  90. */
  91. /**
  92. * @def _TASK_TIMEOUT
  93. * @brief Support for overall task timeout
  94. * @details Any task can be set to time out after a certain period, and timeout can be reset.
  95. * Can be used as an individual Task's watchdog timer.
  96. */
  97. /**
  98. * @def _TASK_OO_CALLBACKS
  99. * @brief Support for callbacks via inheritance
  100. * @details Useful for implementing Tasks as classes derived from the Task class.
  101. * Enables dynamic binding for object-oriented callback approach.
  102. */
  103. /**
  104. * @def _TASK_EXPOSE_CHAIN
  105. * @brief Methods to access tasks in the task chain
  106. * @details Provides access to scheduling chain methods and tasks on the chain.
  107. */
  108. /**
  109. * @def _TASK_SCHEDULING_OPTIONS
  110. * @brief Support for multiple scheduling options
  111. * @details Enables different task scheduling options like TASK_SCHEDULE, TASK_SCHEDULE_NC, and TASK_INTERVAL.
  112. */
  113. /**
  114. * @def _TASK_SELF_DESTRUCT
  115. * @brief Enable tasks to "self-destruct" after disable
  116. * @details Tasks can be set to automatically delete themselves when disabled.
  117. */
  118. /**
  119. * @def _TASK_TICKLESS
  120. * @brief Enable support for tickless sleep on FreeRTOS
  121. * @details Enables support for tickless sleep mode on FreeRTOS systems.
  122. */
  123. /**
  124. * @def _TASK_DO_NOT_YIELD
  125. * @brief Disable yield() method in execute() for ESP chips
  126. * @details Disables automatic yielding in the execute loop for ESP-based systems.
  127. */
  128. /**
  129. * @def _TASK_ISR_SUPPORT
  130. * @brief For ESP chips - place control methods in IRAM
  131. * @details Places critical control methods in IRAM for ESP8266/ESP32 interrupt support.
  132. */
  133. /**
  134. * @def _TASK_NON_ARDUINO
  135. * @brief For non-Arduino use
  136. * @details Enables compilation for non-Arduino environments.
  137. */
  138. /**
  139. * @def _TASK_HEADER_AND_CPP
  140. * @brief Compile CPP file (non-Arduino IDE platforms)
  141. * @details For non-Arduino IDE platforms that require explicit CPP compilation.
  142. */
  143. /**
  144. * @def _TASK_THREAD_SAFE
  145. * @brief Enable additional checking for thread safety
  146. * @details Uses an internal mutex to protect task scheduling methods from preemption.
  147. * Recommended for ESP32 and other MCUs running under preemptive schedulers like FreeRTOS.
  148. */
  149. /** @} */ // End of CompileTimeOptions group
  150. #ifdef _TASK_NON_ARDUINO
  151. #include <stdbool.h>
  152. #include <stdint.h>
  153. #include <stdarg.h>
  154. #include <stddef.h>
  155. #include <stdio.h>
  156. #include <stdlib.h>
  157. #include <string.h>
  158. #include <inttypes.h>
  159. #else
  160. #include <Arduino.h>
  161. #endif
  162. /**
  163. * @brief Forward declaration of Scheduler class
  164. */
  165. class Scheduler;
  166. /**
  167. * @defgroup SchedulingOptions Task Scheduling Options
  168. * @brief Constants defining different task scheduling behaviors
  169. * @{
  170. */
  171. /**
  172. * @def TASK_SCHEDULE
  173. * @brief Default scheduling option
  174. * @details Maintains the original schedule. Tasks may need to "catch up" if delayed.
  175. * If a task is scheduled to run every 10 seconds and starts at 9:00:00,
  176. * the scheduler will try to invoke tasks as close to 9:00:10, 9:00:20 as possible.
  177. */
  178. #define TASK_SCHEDULE 0
  179. /**
  180. * @def TASK_SCHEDULE_NC
  181. * @brief Schedule with no catch-ups (always in the future)
  182. * @details Similar to TASK_SCHEDULE but without "catch up". Tasks are invoked at the next
  183. * scheduled point, but the number of iterations may not be correct if delayed.
  184. */
  185. #define TASK_SCHEDULE_NC 1
  186. /**
  187. * @def TASK_INTERVAL
  188. * @brief Interval-based scheduling (always in the future)
  189. * @details Schedules the next invocation with priority to a "period". A task scheduled for
  190. * 9:00:00 with a 10-second interval that was actually invoked at 9:00:06 will be
  191. * scheduled for the next invocation at 9:00:16.
  192. */
  193. #define TASK_INTERVAL 2
  194. /** @} */ // End of SchedulingOptions group
  195. #ifdef _TASK_DEBUG
  196. #define _TASK_SCOPE public
  197. #else
  198. #define _TASK_SCOPE private
  199. #endif
  200. /**
  201. * @defgroup TaskIterationOptions Task Iteration Options
  202. * @brief Common options for task scheduling iterations
  203. * @{
  204. */
  205. /**
  206. * @def TASK_IMMEDIATE
  207. * @brief Task interval for immediate execution
  208. * @details When used as interval, causes task to execute immediately during next scheduling pass.
  209. */
  210. #define TASK_IMMEDIATE 0
  211. /**
  212. * @def TASK_FOREVER
  213. * @brief Task number of iterations for infinite execution
  214. * @details When used as iteration count, causes task to run indefinitely until explicitly disabled.
  215. */
  216. #define TASK_FOREVER (-1)
  217. /**
  218. * @def TASK_ONCE
  219. * @brief Task single iteration
  220. * @details When used as iteration count, causes task to run only once and then become disabled.
  221. */
  222. #define TASK_ONCE 1
  223. /** @} */ // End of TaskIterationOptions group
  224. /**
  225. * @defgroup IntervalNoDelayOptions Options for setIntervalNodelay() method
  226. * @brief Options controlling how interval changes are handled
  227. * @{
  228. */
  229. /**
  230. * @def TASK_INTERVAL_KEEP
  231. * @brief Keep current execution timing
  232. * @details Maintains the current execution schedule when changing interval.
  233. */
  234. #define TASK_INTERVAL_KEEP 0
  235. /**
  236. * @def TASK_INTERVAL_RECALC
  237. * @brief Recalculate execution timing
  238. * @details Recalculates the next execution time based on the new interval.
  239. */
  240. #define TASK_INTERVAL_RECALC 1
  241. /**
  242. * @def TASK_INTERVAL_RESET
  243. * @brief Reset execution timing
  244. * @details Resets the execution schedule to start from the current time.
  245. */
  246. #define TASK_INTERVAL_RESET 2
  247. /** @} */ // End of IntervalNoDelayOptions group
  248. /**
  249. * @defgroup TimeoutOptions Task Timeout Options
  250. * @brief Options for task timeout functionality
  251. * @{
  252. */
  253. #ifdef _TASK_TIMEOUT
  254. /**
  255. * @def TASK_NOTIMEOUT
  256. * @brief No timeout value
  257. * @details Used to indicate that a task should not have a timeout.
  258. */
  259. #define TASK_NOTIMEOUT 0
  260. #endif
  261. /** @} */ // End of TimeoutOptions group
  262. #ifdef _TASK_PRIORITY
  263. extern Scheduler* iCurrentScheduler;
  264. #endif // _TASK_PRIORITY
  265. #ifdef _TASK_INLINE
  266. #define __TASK_INLINE inline
  267. #else
  268. #define __TASK_INLINE
  269. #endif
  270. #ifdef _TASK_ISR_SUPPORT
  271. #if defined (ARDUINO_ARCH_ESP8266)
  272. #define __TASK_IRAM ICACHE_RAM_ATTR
  273. #endif
  274. #if defined (ARDUINO_ARCH_ESP32)
  275. #define __TASK_IRAM IRAM_ATTR
  276. #endif
  277. #endif
  278. #ifndef __TASK_IRAM
  279. #define __TASK_IRAM
  280. #endif
  281. /**
  282. * @defgroup TimeConstants Time Constants
  283. * @brief Predefined time constants for task intervals
  284. * @details Values are in milliseconds by default, or microseconds when _TASK_MICRO_RES is enabled
  285. * @{
  286. */
  287. #ifndef _TASK_MICRO_RES
  288. /**
  289. * @def TASK_MILLISECOND
  290. * @brief One millisecond interval
  291. */
  292. #define TASK_MILLISECOND 1UL
  293. /**
  294. * @def TASK_SECOND
  295. * @brief One second interval (1000 milliseconds)
  296. */
  297. #define TASK_SECOND 1000UL
  298. /**
  299. * @def TASK_MINUTE
  300. * @brief One minute interval (60000 milliseconds)
  301. */
  302. #define TASK_MINUTE 60000UL
  303. /**
  304. * @def TASK_HOUR
  305. * @brief One hour interval (3600000 milliseconds)
  306. */
  307. #define TASK_HOUR 3600000UL
  308. #else
  309. /**
  310. * @def TASK_MILLISECOND
  311. * @brief One millisecond interval (1000 microseconds)
  312. */
  313. #define TASK_MILLISECOND 1000UL
  314. /**
  315. * @def TASK_SECOND
  316. * @brief One second interval (1000000 microseconds)
  317. */
  318. #define TASK_SECOND 1000000UL
  319. /**
  320. * @def TASK_MINUTE
  321. * @brief One minute interval (60000000 microseconds)
  322. */
  323. #define TASK_MINUTE 60000000UL
  324. /**
  325. * @def TASK_HOUR
  326. * @brief One hour interval (3600000000 microseconds)
  327. */
  328. #define TASK_HOUR 3600000000UL
  329. #endif // _TASK_MICRO_RES
  330. /** @} */ // End of TimeConstants group
  331. #ifdef _TASK_TICKLESS
  332. /**
  333. * @defgroup NextRunStates Task Next Run State Definitions
  334. * @brief State flags for tickless operation next run scheduling
  335. *
  336. * These constants define the next execution state of tasks in tickless mode,
  337. * enabling power-efficient operation by categorizing when tasks need to run.
  338. * Used internally by the scheduler to optimize sleep/wake cycles and minimize
  339. * power consumption in battery-powered applications.
  340. *
  341. * @note Only available when _TASK_TICKLESS compile-time option is enabled
  342. * @see _TASK_TICKLESS
  343. * @{
  344. */
  345. /**
  346. * @brief Undefined next run state
  347. *
  348. * Indicates that the task's next execution time is not defined or has not
  349. * been calculated. This is typically an initial state or error condition
  350. * where the scheduler cannot determine when the task should next execute.
  351. *
  352. * Binary value: 0b0 (0)
  353. *
  354. * @note Used internally by tickless scheduler for state management
  355. * @see _TASK_TICKLESS
  356. * @since Version 3.0.0
  357. */
  358. #define _TASK_NEXTRUN_UNDEFINED 0b0
  359. /**
  360. * @brief Immediate next run state
  361. *
  362. * Indicates that the task should execute immediately on the next scheduler
  363. * pass, bypassing any timing delays. Used for tasks that have been triggered
  364. * by events, forced execution, or have reached their scheduled execution time.
  365. *
  366. * Binary value: 0b1 (1)
  367. *
  368. * @note In tickless mode, prevents the system from entering deep sleep
  369. * @see forceNextIteration(), _TASK_TICKLESS
  370. * @since Version 3.0.0
  371. */
  372. #define _TASK_NEXTRUN_IMMEDIATE 0b1
  373. /**
  374. * @brief Timed next run state
  375. *
  376. * Indicates that the task has a specific future execution time and should
  377. * wait until that time arrives. This enables the tickless scheduler to
  378. * calculate optimal sleep durations and enter power-saving modes until
  379. * the earliest task execution time.
  380. *
  381. * Hexadecimal value: 0x10 (16)
  382. *
  383. * @note Enables deep sleep optimization in tickless mode
  384. * @note Value deliberately different from other states for bit manipulation
  385. * @see _TASK_TICKLESS, getInterval(), delay()
  386. * @since Version 3.0.0
  387. */
  388. #define _TASK_NEXTRUN_TIMED 0x10
  389. /** @} */ // End of NextRunStates group
  390. #endif // _TASK_TICKLESS
  391. #ifdef _TASK_THREAD_SAFE
  392. /**
  393. * @enum _task_request_type_t
  394. * @brief Task request types for thread-safe operations
  395. *
  396. * @details This enum mirrors the Task class API for invocation via requestAction methods
  397. * when _TASK_THREAD_SAFE option is active. It provides a thread-safe way to execute
  398. * task control methods by placing requests on a queue that is processed during the
  399. * scheduler's execute() method.
  400. *
  401. * Each enum value corresponds to a specific Task method that can be called safely
  402. * from other threads or interrupt contexts. The scheduler processes these requests
  403. * atomically during its execution cycle.
  404. *
  405. * @note Only available when compiled with _TASK_THREAD_SAFE support.
  406. *
  407. * @see Scheduler::requestAction()
  408. */
  409. typedef enum {
  410. #ifdef _TASK_STATUS_REQUEST
  411. TASK_SR_REQUEST_SETWAITING, ///< Thread-safe StatusRequest::setWaiting()
  412. TASK_SR_REQUEST_SIGNAL, ///< Thread-safe StatusRequest::signal()
  413. TASK_SR_REQUEST_SIGNALCOMPLETE, ///< Thread-safe StatusRequest::signalComplete()
  414. #ifdef _TASK_TIMEOUT
  415. TASK_SR_REQUEST_SETTIMEOUT, ///< Thread-safe StatusRequest::setTimeout()
  416. TASK_SR_REQUEST_RESETTIMEOUT, ///< Thread-safe StatusRequest::resetTimeout()
  417. #endif // _TASK_TIMEOUT
  418. #endif // _TASK_STATUS_REQUEST
  419. #ifdef _TASK_LTS_POINTER
  420. TASK_REQUEST_SETLTSPOINTER, ///< Thread-safe Task::setLtsPointer()
  421. #endif
  422. #ifdef _TASK_SELF_DESTRUCT
  423. TASK_REQUEST_SETSELFDESTRUCT, ///< Thread-safe Task::setSelfDestruct()
  424. #endif // _TASK_SELF_DESTRUCT
  425. #ifdef _TASK_SCHEDULING_OPTIONS
  426. TASK_REQUEST_SETSCHEDULINGOPTION, ///< Thread-safe Task::setSchedulingOption()
  427. #endif // _TASK_SCHEDULING_OPTIONS
  428. #ifdef _TASK_TIMEOUT
  429. TASK_REQUEST_SETTIMEOUT, ///< Thread-safe Task::setTimeout()
  430. TASK_REQUEST_RESETTIMEOUT, ///< Thread-safe Task::resetTimeout()
  431. #endif // _TASK_TIMEOUT
  432. #ifdef _TASK_STATUS_REQUEST
  433. TASK_REQUEST_WAITFOR, ///< Thread-safe Task::waitFor()
  434. TASK_REQUEST_WAITFORDELAYED, ///< Thread-safe Task::waitForDelayed()
  435. #endif // _TASK_STATUS_REQUEST
  436. #ifdef _TASK_WDT_IDS
  437. TASK_REQUEST_SETID, ///< Thread-safe Task::setId()
  438. TASK_REQUEST_SETCONTROLPOINT, ///< Thread-safe Task::setControlPoint()
  439. #endif // _TASK_WDT_IDS
  440. TASK_REQUEST_ENABLE, ///< Thread-safe Task::enable()
  441. TASK_REQUEST_ENABLEIFNOT, ///< Thread-safe Task::enableIfNot()
  442. TASK_REQUEST_ENABLEDELAYED, ///< Thread-safe Task::enableDelayed()
  443. TASK_REQUEST_RESTART, ///< Thread-safe Task::restart()
  444. TASK_REQUEST_RESTARTDELAYED, ///< Thread-safe Task::restartDelayed()
  445. TASK_REQUEST_DELAY, ///< Thread-safe Task::delay()
  446. TASK_REQUEST_ADJUST, ///< Thread-safe Task::adjust()
  447. TASK_REQUEST_FORCENEXTITERATION, ///< Thread-safe Task::forceNextIteration()
  448. TASK_REQUEST_DISABLE, ///< Thread-safe Task::disable()
  449. TASK_REQUEST_ABORT, ///< Thread-safe Task::abort()
  450. TASK_REQUEST_CANCEL, ///< Thread-safe Task::cancel()
  451. TASK_REQUEST_SET, ///< Thread-safe Task::set()
  452. TASK_REQUEST_SETINTERVAL, ///< Thread-safe Task::setInterval()
  453. TASK_REQUEST_SETINTERVALNODELAY, ///< Thread-safe Task::setIntervalNodelay()
  454. TASK_REQUEST_SETITERATIONS, ///< Thread-safe Task::setIterations()
  455. TASK_REQUEST_SETCALLBACK, ///< Thread-safe Task::setCallback()
  456. TASK_REQUEST_SETONENABLE, ///< Thread-safe Task::setOnEnable()
  457. TASK_REQUEST_SETONDISABLE ///< Thread-safe Task::setOnDisable()
  458. } _task_request_type_t;
  459. #ifdef _TASK_STATUS_REQUEST
  460. // void setWaiting(unsigned int aCount = 1);
  461. #define TASK_SR_REQUEST_SETWAITING_1 TASK_SR_REQUEST_SETWAITING
  462. #define TASK_SR_REQUEST_SETWAITING_1_DEFAULT 1
  463. // __TASK_IRAM signal(int aStatus = 0);
  464. #define TASK_SR_REQUEST_SIGNAL_1 TASK_SR_REQUEST_SIGNAL
  465. #define TASK_SR_REQUEST_SIGNAL_1_DEFAULT 0
  466. // __TASK_IRAM signalComplete(int aStatus = 0);
  467. #define TASK_SR_REQUEST_SIGNALCOMPLETE_1 TASK_SR_REQUEST_SIGNALCOMPLETE
  468. #define TASK_SR_REQUEST_SIGNALCOMPLETE_1_DEFAULT 0
  469. #ifdef _TASK_TIMEOUT
  470. // void setTimeout(unsigned long aTimeout)
  471. #define TASK_SR_REQUEST_SETTIMEOUT_1 TASK_SR_REQUEST_SETTIMEOUT
  472. // void resetTimeout();
  473. #define TASK_SR_REQUEST_RESETTIMEOUT_0 TASK_SR_REQUEST_RESETTIMEOUT
  474. #endif // _TASK_TIMEOUT
  475. #endif
  476. #ifdef _TASK_LTS_POINTER
  477. // void setLtsPointer(void *aPtr);
  478. #define TASK_REQUEST_SETLTSPOINTER_1 TASK_REQUEST_SETLTSPOINTER
  479. #endif
  480. #ifdef _TASK_SELF_DESTRUCT
  481. // void setSelfDestruct(bool aSelfDestruct=true)
  482. #define TASK_REQUEST_SETSELFDESTRUCT_1 TASK_REQUEST_SETSELFDESTRUCT
  483. #define TASK_REQUEST_SETSELFDESTRUCT_1_DEFAULT true
  484. #endif
  485. #ifdef _TASK_SCHEDULING_OPTIONS
  486. // void setSchedulingOption(unsigned int aOption)
  487. #define TASK_REQUEST_SETSCHEDULINGOPTION_1 TASK_REQUEST_SETSCHEDULINGOPTION
  488. #endif
  489. #ifdef _TASK_TIMEOUT
  490. // void setTimeout(unsigned long aTimeout, bool aReset=false);
  491. #define TASK_REQUEST_SETTIMEOUT_2 TASK_REQUEST_SETTIMEOUT
  492. #define TASK_REQUEST_SETTIMEOUT_2_DEFAULT false
  493. // void resetTimeout();
  494. #define TASK_REQUEST_RESETTIMEOUT_0 TASK_REQUEST_RESETTIMEOUT
  495. #endif // _TASK_TIMEOUT
  496. #ifdef _TASK_STATUS_REQUEST
  497. // bool waitFor(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1)
  498. #define TASK_REQUEST_WAITFOR_3 TASK_REQUEST_WAITFOR
  499. #define TASK_REQUEST_WAITFOR_2_DEFAULT 0
  500. #define TASK_REQUEST_WAITFOR_3_DEFAULT 1
  501. // bool waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1)
  502. #define TASK_REQUEST_WAITFORDELAYED_3 TASK_REQUEST_WAITFORDELAYED
  503. #define TASK_REQUEST_WAITFORDELAYED_2_DEFAULT 0
  504. #define TASK_REQUEST_WAITFORDELAYED_3_DEFAULT 1
  505. #endif // _TASK_STATUS_REQUEST
  506. #ifdef _TASK_WDT_IDS
  507. // __TASK_INLINE void setId(unsigned int aID) ;
  508. #define TASK_REQUEST_SETID_1 TASK_REQUEST_SETID
  509. // __TASK_INLINE void setControlPoint(unsigned int aPoint) ;
  510. #define TASK_REQUEST_SETCONTROLPOINT_1 TASK_REQUEST_SETCONTROLPOINT
  511. #endif // _TASK_WDT_IDS
  512. // bool __TASK_IRAM enable();
  513. #define TASK_REQUEST_ENABLE_0 TASK_REQUEST_ENABLE
  514. // bool __TASK_IRAM enableIfNot();
  515. #define TASK_REQUEST_ENABLEIFNOT_0 TASK_REQUEST_ENABLEIFNOT
  516. // bool __TASK_IRAM enableDelayed(unsigned long aDelay=0);
  517. #define TASK_REQUEST_ENABLEDELAYED_1 TASK_REQUEST_ENABLEDELAYED
  518. #define TASK_REQUEST_ENABLEDELAYED_1_DEFAULT 0
  519. // bool __TASK_IRAM restart();
  520. #define TASK_REQUEST_RESTART_0 TASK_REQUEST_RESTART
  521. // bool __TASK_IRAM restartDelayed(unsigned long aDelay=0);
  522. #define TASK_REQUEST_RESTARTDELAYED_1 TASK_REQUEST_RESTARTDELAYED
  523. #define TASK_REQUEST_RESTARTDELAYED_1_DEFAULT 0
  524. // void __TASK_IRAM delay(unsigned long aDelay=0);
  525. #define TASK_REQUEST_DELAY_1 TASK_REQUEST_DELAY
  526. #define TASK_REQUEST_DELAY_1_DEFAULT 0
  527. // void adjust(long aInterval);
  528. #define TASK_REQUEST_ADJUST_1 TASK_REQUEST_ADJUST
  529. // void __TASK_IRAM forceNextIteration();
  530. #define TASK_REQUEST_FORCENEXTITERATION_0 TASK_REQUEST_FORCENEXTITERATION
  531. // bool disable();
  532. #define TASK_REQUEST_DISABLE_0 TASK_REQUEST_DISABLE
  533. // void abort();
  534. #define TASK_REQUEST_ABORT_0 TASK_REQUEST_ABORT
  535. // void cancel();
  536. #define TASK_REQUEST_CANCEL_0 TASK_REQUEST_CANCEL
  537. // void set(unsigned long aInterval, long aIterations, TaskCallback aCallback,TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  538. #define TASK_REQUEST_SET_5 TASK_REQUEST_SET
  539. #define TASK_REQUEST_SET_4_DEFAULT NULL
  540. #define TASK_REQUEST_SET_5_DEFAULT NULL
  541. // void setInterval(unsigned long aInterval);
  542. #define TASK_REQUEST_SETINTERVAL_1 TASK_REQUEST_SETINTERVAL
  543. // void setIntervalNodelay(unsigned long aInterval, unsigned int aOption = TASK_INTERVAL_KEEP);
  544. #define TASK_REQUEST_SETINTERVALNODELAY_2 TASK_REQUEST_SETINTERVALNODELAY
  545. #define TASK_REQUEST_SETINTERVALNODELAY_2_DEFAULT TASK_INTERVAL_KEEP
  546. // void setIterations(long aIterations);
  547. #define TASK_REQUEST_SETITERATIONS_1 TASK_REQUEST_SETITERATIONS
  548. // void setCallback(TaskCallback aCallback)
  549. #define TASK_REQUEST_SETCALLBACK_1 TASK_REQUEST_SETCALLBACK
  550. // setOnEnable(TaskOnEnable aCallback) ;
  551. #define TASK_REQUEST_SETONENABLE_1 TASK_REQUEST_SETONENABLE
  552. // setOnDisable(TaskOnDisable aCallback) ;
  553. #define TASK_REQUEST_SETONDISABLE_1 TASK_REQUEST_SETONDISABLE
  554. /**
  555. * @struct _task_request_t
  556. * @brief Structure for thread-safe task operation requests
  557. *
  558. * @details This structure is used to call Scheduler::requestAction() and provide parameters
  559. * to the respective API method in a thread-safe manner. When _TASK_THREAD_SAFE is enabled,
  560. * this structure allows tasks to be controlled safely from interrupt contexts or other threads
  561. * by queuing requests that are processed atomically during the scheduler's execute() cycle.
  562. *
  563. * The structure contains the request type and up to 5 parameters that correspond to the
  564. * parameters of the target Task or StatusRequest method being called. The scheduler will
  565. * unpack these parameters and call the appropriate method during its execution.
  566. *
  567. * Usage example:
  568. * @code
  569. * _task_request_t request;
  570. * request.req_type = TASK_REQUEST_ENABLE;
  571. * request.object_ptr = &myTask;
  572. * // param1-param5 not needed for enable()
  573. * scheduler.requestAction(&request);
  574. * @endcode
  575. *
  576. * @note Only available when compiled with _TASK_THREAD_SAFE support.
  577. *
  578. * @see Scheduler::requestAction(), _task_request_type_t
  579. */
  580. typedef struct {
  581. _task_request_type_t req_type; ///< Type of request (corresponds to Task/StatusRequest method)
  582. void* object_ptr; ///< Pointer to Task or StatusRequest object to operate on
  583. unsigned long param1; ///< First parameter for the target method (if needed)
  584. unsigned long param2; ///< Second parameter for the target method (if needed)
  585. unsigned long param3; ///< Third parameter for the target method (if needed)
  586. unsigned long param4; ///< Fourth parameter for the target method (if needed)
  587. unsigned long param5; ///< Fifth parameter for the target method (if needed)
  588. } _task_request_t;
  589. #endif //_TASK_THREAD_SAFE
  590. #ifdef _TASK_STATUS_REQUEST
  591. /**
  592. * @defgroup StatusRequestCodes Status Request Return Codes
  593. * @brief Status codes returned by StatusRequest operations
  594. * @{
  595. */
  596. /**
  597. * @def TASK_SR_OK
  598. * @brief Successful completion status
  599. * @details Default successful completion status for StatusRequest operations.
  600. */
  601. #define TASK_SR_OK 0
  602. /**
  603. * @def TASK_SR_ERROR
  604. * @brief General error status
  605. * @details Indicates an error condition occurred during StatusRequest operation.
  606. */
  607. #define TASK_SR_ERROR (-1)
  608. /**
  609. * @def TASK_SR_CANCEL
  610. * @brief Cancelled status
  611. * @details Indicates the StatusRequest operation was cancelled.
  612. */
  613. #define TASK_SR_CANCEL (-32766)
  614. /**
  615. * @def TASK_SR_ABORT
  616. * @brief Aborted status
  617. * @details Indicates the StatusRequest operation was aborted.
  618. */
  619. #define TASK_SR_ABORT (-32767)
  620. /**
  621. * @def TASK_SR_TIMEOUT
  622. * @brief Timeout status
  623. * @details Indicates the StatusRequest operation timed out.
  624. */
  625. #define TASK_SR_TIMEOUT (-32768)
  626. /** @} */ // End of StatusRequestCodes group
  627. /**
  628. * @defgroup StatusRequestModes Status Request Internal Modes
  629. * @brief Internal mode constants for StatusRequest operations
  630. * @{
  631. */
  632. /**
  633. * @def _TASK_SR_NODELAY
  634. * @brief No delay mode for StatusRequest
  635. */
  636. #define _TASK_SR_NODELAY 1
  637. /**
  638. * @def _TASK_SR_DELAY
  639. * @brief Delay mode for StatusRequest
  640. */
  641. #define _TASK_SR_DELAY 2
  642. /** @} */ // End of StatusRequestModes group
  643. /**
  644. * @class StatusRequest
  645. * @brief Status Request object for event-driven task invocation
  646. *
  647. * @details StatusRequest objects allow tasks to wait on an event and signal event completion to each other.
  648. * This enables event-driven programming where one task can "signal" completion of its function via a
  649. * StatusRequest object, and other tasks can "wait" on the same StatusRequest object.
  650. *
  651. * Key features:
  652. * - Can wait for multiple events (set via setWaiting())
  653. * - Supports timeout functionality
  654. * - Provides completion status codes
  655. * - Thread-safe signaling mechanisms
  656. *
  657. * @note Each task has an internal StatusRequest object that is:
  658. * - Always waits on 1 event (completion of this task)
  659. * - Activated (set to "waiting" status) after Task is enabled
  660. * - Completed after Task is disabled
  661. *
  662. * @see Task::waitFor(), Task::waitForDelayed()
  663. */
  664. class StatusRequest {
  665. friend class Scheduler;
  666. public:
  667. /**
  668. * @brief Default constructor
  669. * @details Creates Status Request object with "completed" status on creation.
  670. */
  671. __TASK_INLINE StatusRequest();
  672. /**
  673. * @brief Activates Status Request object
  674. * @param aCount Number of events to wait for (default = 1)
  675. * @details By default each object waits on one event only. If aCount is supplied,
  676. * StatusRequest can wait on multiple events. For example, setWaiting(3) will wait
  677. * on three signals - useful for waiting for completion of measurements from 3 sensors.
  678. */
  679. __TASK_INLINE void setWaiting(unsigned int aCount = 1);
  680. /**
  681. * @brief Signals completion of one event
  682. * @param aStatus Completion code (default = 0)
  683. * @return true if signal was processed successfully
  684. * @details Signals completion of the event to the StatusRequest object and passes
  685. * a completion code. Passing a negative status code is considered reporting an error
  686. * condition and will complete the status request regardless of how many outstanding
  687. * signals it is still waiting for. Only the latest status code is kept.
  688. */
  689. __TASK_INLINE bool signal(int aStatus = 0);
  690. /**
  691. * @brief Signals completion of ALL events
  692. * @param aStatus Completion code (default = 0)
  693. * @details Signals completion of ALL events to the StatusRequest object and passes
  694. * a completion code. The status request completes regardless of how many events
  695. * it is still waiting on.
  696. */
  697. __TASK_INLINE void signalComplete(int aStatus = 0);
  698. /**
  699. * @brief Check if status request is pending (deprecated)
  700. * @return true if status request is still waiting for events
  701. * @deprecated Use isPending() instead
  702. */
  703. __TASK_INLINE bool pending() { return isPending(); };
  704. /**
  705. * @brief Check if status request is pending
  706. * @return true if status request is still waiting for events to happen
  707. */
  708. __TASK_INLINE bool isPending();
  709. /**
  710. * @brief Check if status request is completed (deprecated)
  711. * @return true if status request event has completed
  712. * @deprecated Use isCompleted() instead
  713. */
  714. __TASK_INLINE bool completed() { return isCompleted(); };
  715. /**
  716. * @brief Check if status request is completed
  717. * @return true if status request event has completed
  718. */
  719. __TASK_INLINE bool isCompleted();
  720. /**
  721. * @brief Get the status code
  722. * @return The status code passed to signal() and signalComplete() methods
  723. * @details Any positive number is considered successful completion status.
  724. * A 0 (zero) is considered default successful completion status.
  725. * Any negative number is considered an error code and unsuccessful completion.
  726. */
  727. __TASK_INLINE int getStatus();
  728. /**
  729. * @brief Get count of remaining events
  730. * @return The count of events not yet completed
  731. * @details Typically by default a StatusRequest object only waits on 1 event.
  732. * However, when waiting on multiple events, returns number of events not yet completed.
  733. */
  734. __TASK_INLINE int getCount();
  735. #ifdef _TASK_TIMEOUT
  736. /**
  737. * @brief Set timeout for this StatusRequest object
  738. * @param aTimeout Timeout interval in milliseconds (or microseconds)
  739. * @details When enabled, the activated StatusRequest object will complete with
  740. * the code TASK_SR_TIMEOUT if no other process calls its signal() or signalComplete() method.
  741. */
  742. __TASK_INLINE void setTimeout(unsigned long aTimeout) { iTimeout = aTimeout; };
  743. /**
  744. * @brief Get timeout interval
  745. * @return The timeout interval for the current StatusRequest object
  746. * @details This is the full original interval, not the remaining time.
  747. */
  748. __TASK_INLINE unsigned long getTimeout() { return iTimeout; };
  749. /**
  750. * @brief Reset timeout counter
  751. * @details Resets the current timeout counter to the original value.
  752. * The timeout countdown starts from the beginning again.
  753. */
  754. __TASK_INLINE void resetTimeout();
  755. /**
  756. * @brief Get time until timeout
  757. * @return Number of milliseconds (or microseconds) until timeout
  758. * @details The value could be negative if the timeout has already occurred.
  759. */
  760. __TASK_INLINE long untilTimeout();
  761. #endif
  762. _TASK_SCOPE:
  763. unsigned int iCount; // number of statuses to wait for. waiting for more that 65000 events seems unreasonable: unsigned int should be sufficient
  764. int iStatus; // status of the last completed request. negative = error; zero = OK; positive = OK with a specific status (see TASK_SR_ constants)
  765. #ifdef _TASK_TIMEOUT
  766. unsigned long iTimeout; // Task overall timeout
  767. unsigned long iStarttime; // millis at task start time
  768. #endif // _TASK_TIMEOUT
  769. };
  770. #endif // _TASK_STATUS_REQUEST
  771. /**
  772. * @defgroup CallbackTypes Task Callback Types
  773. * @brief Type definitions for task callback functions
  774. * @{
  775. */
  776. #ifdef _TASK_STD_FUNCTION
  777. #include <functional>
  778. /**
  779. * @typedef TaskCallback
  780. * @brief Main task callback function type (std::function version)
  781. * @details Function called periodically when task is executed. Should be non-blocking
  782. * and return quickly to maintain cooperative multitasking behavior.
  783. */
  784. typedef std::function<void()> TaskCallback;
  785. /**
  786. * @typedef TaskOnDisable
  787. * @brief Task disable callback function type (std::function version)
  788. * @details Function called when task is disabled. Used for cleanup operations.
  789. */
  790. typedef std::function<void()> TaskOnDisable;
  791. /**
  792. * @typedef TaskOnEnable
  793. * @brief Task enable callback function type (std::function version)
  794. * @details Function called when task is enabled. Should return true to enable task,
  795. * false to keep task disabled. Used for initialization operations.
  796. */
  797. typedef std::function<bool()> TaskOnEnable;
  798. #else
  799. /**
  800. * @typedef TaskCallback
  801. * @brief Main task callback function pointer type
  802. * @details Function called periodically when task is executed. Should be non-blocking
  803. * and return quickly to maintain cooperative multitasking behavior.
  804. */
  805. typedef void (*TaskCallback)();
  806. /**
  807. * @typedef TaskOnDisable
  808. * @brief Task disable callback function pointer type
  809. * @details Function called when task is disabled. Used for cleanup operations.
  810. */
  811. typedef void (*TaskOnDisable)();
  812. /**
  813. * @typedef TaskOnEnable
  814. * @brief Task enable callback function pointer type
  815. * @details Function called when task is enabled. Should return true to enable task,
  816. * false to keep task disabled. Used for initialization operations.
  817. */
  818. typedef bool (*TaskOnEnable)();
  819. #endif // _TASK_STD_FUNCTION
  820. /** @} */ // End of CallbackTypes group
  821. #ifdef _TASK_SLEEP_ON_IDLE_RUN
  822. /**
  823. * @typedef SleepCallback
  824. * @brief Sleep function callback type
  825. * @param aDuration Duration to sleep in milliseconds
  826. * @details Function pointer type for custom sleep implementations during idle periods.
  827. */
  828. typedef void (*SleepCallback)( unsigned long aDuration );
  829. /**
  830. * @brief Global pointer to scheduler that controls sleep functionality
  831. */
  832. extern Scheduler* iSleepScheduler;
  833. /**
  834. * @brief Global pointer to custom sleep method
  835. */
  836. extern SleepCallback iSleepMethod;
  837. #endif // _TASK_SLEEP_ON_IDLE_RUN
  838. /**
  839. * @struct _task_status
  840. * @brief Internal task status structure
  841. * @details Bit-packed structure containing task state flags for efficient memory usage.
  842. * This structure tracks various task states and conditions.
  843. */
  844. typedef struct {
  845. bool enabled : 1; ///< Indicates that task is enabled or not
  846. bool inonenable : 1; ///< Indicates that task execution is inside OnEnable method (preventing infinite loops)
  847. bool canceled : 1; ///< Indication that task has been canceled prior to normal end of all iterations or regular call to disable()
  848. #ifdef _TASK_SELF_DESTRUCT
  849. bool selfdestruct : 1; ///< Indication that task has been requested to self-destruct on disable
  850. bool sd_request : 1; ///< Request for scheduler to delete task object and take task out of the queue
  851. #endif // _TASK_SELF_DESTRUCT
  852. #ifdef _TASK_STATUS_REQUEST
  853. uint8_t waiting : 2; ///< Indication if task is waiting on the status request
  854. #endif // _TASK_STATUS_REQUEST
  855. #ifdef _TASK_TIMEOUT
  856. bool timeout : 1; ///< Indication if task timed out
  857. #endif // _TASK_TIMEOUT
  858. } _task_status;
  859. /**
  860. * @class Task
  861. * @brief Core task class for cooperative multitasking
  862. *
  863. * @details A "Task" is an action, a part of the program logic, which requires scheduled execution.
  864. * A concept of Task combines the following aspects:
  865. * - Program code performing specific activities (callback methods)
  866. * - Execution interval
  867. * - Number of execution iterations
  868. * - (Optionally) Execution start event (Status Request)
  869. * - (Optionally) Pointer to a Local Task Storage area
  870. *
  871. * Tasks perform certain functions, which could require periodic or one-time execution,
  872. * update of specific variables, or waiting for specific events. Tasks also could be
  873. * controlling specific hardware, or triggered by hardware interrupts.
  874. *
  875. * For execution purposes Tasks are linked into execution chains, which are processed
  876. * by the Scheduler in the order they were added (linked together).
  877. *
  878. * Key Features:
  879. * - Cooperative multitasking (non-preemptive)
  880. * - Event-driven execution via StatusRequest objects
  881. * - Dynamic parameter adjustment during runtime
  882. * - Support for callback chaining and state machines
  883. * - Built-in timeout and watchdog functionality
  884. * - Local task storage for task-specific data
  885. *
  886. * @note Tasks are responsible for supporting cooperative multitasking by being "good neighbors",
  887. * i.e., running their callback methods quickly in a non-blocking way, and releasing control
  888. * back to the scheduler as soon as possible.
  889. *
  890. * @see Scheduler, StatusRequest
  891. */
  892. class Task {
  893. friend class Scheduler;
  894. public:
  895. /**
  896. * @brief Task constructor with parameters
  897. * @param aInterval Execution interval in milliseconds (or microseconds if _TASK_MICRO_RES enabled) (default = 0)
  898. * @param aIterations Number of iterations, -1 for indefinite execution (default = 0)
  899. * @param aScheduler Optional reference to existing scheduler. If supplied (not NULL) this task will be appended to the task chain (default = NULL)
  900. * @param aEnable Optional. Value of true will create task enabled (default = false)
  901. *
  902. * @details Creates a task that is scheduled to run every aInterval milliseconds, aIterations times.
  903. * All tasks are created disabled by default (unless aEnable = true). You have to explicitly enable
  904. * the task for execution.
  905. *
  906. * @note Tasks do not remember the number of iterations set initially. After the iterations are done,
  907. * internal iteration counter is 0. If you need to perform another set of iterations, you need to set
  908. * the number of iterations again.
  909. *
  910. * @note Tasks which performed all their iterations remain active.
  911. */
  912. #ifdef _TASK_OO_CALLBACKS
  913. __TASK_INLINE Task(unsigned long aInterval=0, long aIterations=0, Scheduler* aScheduler=NULL, bool aEnable=false
  914. #ifdef _TASK_SELF_DESTRUCT
  915. , bool aSelfDestruct=false);
  916. #else
  917. );
  918. #endif // #ifdef _TASK_SELF_DESTRUCT
  919. #else
  920. /**
  921. * @brief Task constructor with callback parameters
  922. * @param aInterval Execution interval in milliseconds (or microseconds if _TASK_MICRO_RES enabled) (default = 0)
  923. * @param aIterations Number of iterations, -1 for indefinite execution (default = 0)
  924. * @param aCallback Pointer to the void callback method without parameters (default = NULL)
  925. * @param aScheduler Optional reference to existing scheduler. If supplied (not NULL) this task will be appended to the task chain (default = NULL)
  926. * @param aEnable Optional. Value of true will create task enabled (default = false)
  927. * @param aOnEnable Pointer to the bool OnEnable callback method without parameters, invoked when task is enabled (default = NULL)
  928. * @param aOnDisable Pointer to the void OnDisable method without parameters, invoked when task is disabled (default = NULL)
  929. *
  930. * @details Creates a task with callback methods. OnEnable method returns true if task should be enabled,
  931. * false if it should remain disabled. OnDisable method is called when task is disabled.
  932. *
  933. * @note OnEnable callback method is called immediately when task is enabled, which could be well ahead
  934. * of the scheduled execution time of the task. It is advisable to explicitly enable tasks with OnEnable
  935. * methods after all initialization methods completed (e.g., at the end of setup() method).
  936. */
  937. __TASK_INLINE Task(unsigned long aInterval=0, long aIterations=0, TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, bool aEnable=false, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL
  938. #ifdef _TASK_SELF_DESTRUCT
  939. , bool aSelfDestruct=false);
  940. #else
  941. );
  942. #endif // #ifdef _TASK_SELF_DESTRUCT
  943. #endif // _TASK_OO_CALLBACKS
  944. #ifdef _TASK_STATUS_REQUEST
  945. #ifdef _TASK_OO_CALLBACKS
  946. /**
  947. * @brief Constructor for StatusRequest-based tasks (Object-Oriented callbacks)
  948. * @param aScheduler Pointer to scheduler
  949. * @details Creates a Task for activation on event. Such tasks must run waitFor() method,
  950. * their interval, iteration and enabled status will be set by that method.
  951. */
  952. __TASK_INLINE Task(Scheduler* aScheduler);
  953. #else
  954. /**
  955. * @brief Constructor for StatusRequest-based tasks (Function pointer callbacks)
  956. * @param aCallback Pointer to callback function
  957. * @param aScheduler Pointer to scheduler
  958. * @param aOnEnable Pointer to OnEnable callback (default = NULL)
  959. * @param aOnDisable Pointer to OnDisable callback (default = NULL)
  960. * @details Creates a Task for activation on event. Such tasks must run waitFor() method,
  961. * their interval, iteration and enabled status will be set by that method.
  962. */
  963. __TASK_INLINE Task(TaskCallback aCallback, Scheduler* aScheduler, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  964. #endif // _TASK_OO_CALLBACKS
  965. #endif // _TASK_STATUS_REQUEST
  966. /**
  967. * @brief Virtual destructor
  968. * @details Properly destroys the task object and cleans up resources.
  969. */
  970. virtual __TASK_INLINE ~Task();
  971. #ifdef _TASK_TIMEOUT
  972. /**
  973. * @brief Set overall task timeout
  974. * @param aTimeout Timeout period in milliseconds (or microseconds)
  975. * @param aReset Whether to reset timeout counter (default = false)
  976. * @details Any task can be set to time out after a certain period of time.
  977. * Timeout can be reset, so it can be used as an individual Task's watchdog timer.
  978. */
  979. __TASK_INLINE void setTimeout(unsigned long aTimeout, bool aReset=false);
  980. /**
  981. * @brief Reset timeout counter
  982. * @details Resets the timeout counter to start counting from the beginning.
  983. */
  984. __TASK_INLINE void resetTimeout();
  985. /**
  986. * @brief Get timeout value
  987. * @return Current timeout value in milliseconds (or microseconds)
  988. */
  989. __TASK_INLINE unsigned long getTimeout();
  990. /**
  991. * @brief Get time until timeout
  992. * @return Number of milliseconds (or microseconds) until timeout occurs
  993. * @details Returns negative value if timeout has already occurred.
  994. */
  995. __TASK_INLINE long untilTimeout();
  996. /**
  997. * @brief Check if task has timed out (deprecated)
  998. * @return true if task has timed out
  999. * @deprecated Use isTimedOut() instead
  1000. */
  1001. __TASK_INLINE bool timedOut() { return isTimedOut(); };
  1002. /**
  1003. * @brief Check if task has timed out
  1004. * @return true if task has timed out
  1005. */
  1006. __TASK_INLINE bool isTimedOut();
  1007. #endif
  1008. /**
  1009. * @brief Enable the task
  1010. * @return true if task was successfully enabled
  1011. * @details Enables the task and schedules it for immediate execution (without delay) at this or next
  1012. * scheduling pass. Scheduler will execute the next pass without any delay because there is a task
  1013. * which was enabled and requires execution.
  1014. *
  1015. * @note If task being enabled is not assigned to a scheduler and is not part of execution chain,
  1016. * then task will not be enabled.
  1017. *
  1018. * @note enable() invokes task's OnEnable method (if not NULL) immediately, which can prepare task
  1019. * for execution. OnEnable must return true for task to be enabled. If OnEnable returns false,
  1020. * task remains disabled.
  1021. *
  1022. * @warning OnEnable is invoked every time enable() is called, regardless if task is already enabled.
  1023. * Alignment to current millis() is performed after OnEnable exits.
  1024. */
  1025. __TASK_INLINE bool enable();
  1026. /**
  1027. * @brief Enable the task only if it was previously disabled
  1028. * @return Previous enable state: true if task was already enabled, false if task was disabled
  1029. * @details Since enable() schedules Task for execution immediately, this method provides a way
  1030. * to activate tasks and schedule them for immediate execution only if they are not active already.
  1031. * All NOTES from the enable() method apply.
  1032. */
  1033. __TASK_INLINE bool enableIfNot();
  1034. /**
  1035. * @brief Enable the task with delay
  1036. * @param aDelay Delay before first execution in milliseconds (default = 0)
  1037. * @return true if task was successfully enabled
  1038. * @details Enables the task and schedules it for execution after a specific delay.
  1039. */
  1040. __TASK_INLINE bool enableDelayed(unsigned long aDelay=0);
  1041. /**
  1042. * @brief Restart the task
  1043. * @return true if task was successfully restarted
  1044. * @details For tasks with limited number of iterations only, restart method will re-enable the task,
  1045. * set the number of iterations back to last set value, and schedule task for execution as soon as possible.
  1046. */
  1047. __TASK_INLINE bool restart();
  1048. /**
  1049. * @brief Restart the task with delay
  1050. * @param aDelay Delay before first execution in milliseconds (default = 0)
  1051. * @return true if task was successfully restarted
  1052. * @details Same as restart() method, with the only difference being that Task is scheduled to run
  1053. * first iteration after a delay.
  1054. */
  1055. __TASK_INLINE bool restartDelayed(unsigned long aDelay=0);
  1056. /**
  1057. * @brief Delay the task execution
  1058. * @param aDelay Delay in milliseconds (default = 0)
  1059. * @details Schedules the task for execution after a delay, but does not change the enabled/disabled
  1060. * status of the task. A delay of 0 (zero) will delay task for current execution interval.
  1061. * Use forceNextIteration() method to force execution during immediate next scheduling pass.
  1062. */
  1063. __TASK_INLINE void delay(unsigned long aDelay=0);
  1064. /**
  1065. * @brief Adjust task interval
  1066. * @param aInterval New interval value (can be negative for adjustment)
  1067. * @details Adjusts the task execution interval by the specified amount.
  1068. */
  1069. __TASK_INLINE void adjust(long aInterval);
  1070. /**
  1071. * @brief Force next iteration to execute immediately
  1072. * @details Schedules the task for execution during immediate next scheduling pass.
  1073. * The Task must be already enabled prior to this method. Task's schedule is adjusted
  1074. * to run from this moment in time.
  1075. *
  1076. * @note If a task was running every 10 seconds: 10, 20, 30, calling forceNextIteration
  1077. * at 44th second will make subsequent schedule look like: 44, 54, 64, 74, ..
  1078. */
  1079. __TASK_INLINE void forceNextIteration();
  1080. /**
  1081. * @brief Disable the task
  1082. * @return Previous enabled state: true if task was enabled, false otherwise
  1083. * @details Scheduler will not execute this task any longer, even if it remains in the chain.
  1084. * Task can be later re-enabled for execution. If not NULL, task's OnDisable method is invoked
  1085. * almost immediately (actually during the next scheduling pass).
  1086. * OnDisable is invoked only if task was in enabled state.
  1087. */
  1088. __TASK_INLINE bool disable();
  1089. /**
  1090. * @brief Abort the task
  1091. * @details Immediately stops task execution and marks it as aborted.
  1092. * Different from disable() in that it indicates abnormal termination.
  1093. * OnDisable method is NOT invoked for Aborted tasks.
  1094. */
  1095. __TASK_INLINE void abort();
  1096. /**
  1097. * @brief Cancel the task
  1098. * @details Marks the task as cancelled, indicating it was stopped before normal completion.
  1099. * OnDisable method is invoked if task was in enabled state.
  1100. */
  1101. __TASK_INLINE void cancel();
  1102. /**
  1103. * @brief Check if task is enabled
  1104. * @return true if task is enabled
  1105. */
  1106. __TASK_INLINE bool isEnabled();
  1107. /**
  1108. * @brief Check if task is cancelled
  1109. * @return true if task has been cancelled
  1110. */
  1111. __TASK_INLINE bool isCanceled();
  1112. /**
  1113. * @brief Check if task is cancelled (deprecated)
  1114. * @return true if task has been cancelled
  1115. * @deprecated Use isCanceled() instead
  1116. */
  1117. __TASK_INLINE bool canceled() { return isCanceled(); };
  1118. #ifdef _TASK_SCHEDULING_OPTIONS
  1119. /**
  1120. * @brief Get the current scheduling option for this task
  1121. *
  1122. * Returns the current scheduling behavior option that determines how the task's
  1123. * interval and iterations are managed during execution.
  1124. *
  1125. * Available scheduling options:
  1126. * - TASK_SCHEDULE: Default behavior - interval countdown starts after OnEnable
  1127. * - TASK_SCHEDULE_NC: No countdown - interval countdown starts immediately upon enable
  1128. * - TASK_INTERVAL: Interval mode - maintains exact intervals regardless of execution time
  1129. *
  1130. * @return unsigned int Current scheduling option value (TASK_SCHEDULE, TASK_SCHEDULE_NC, or TASK_INTERVAL)
  1131. *
  1132. * @note This method is only available when _TASK_SCHEDULING_OPTIONS compile-time option is enabled
  1133. * @see setSchedulingOption(), TASK_SCHEDULE, TASK_SCHEDULE_NC, TASK_INTERVAL
  1134. * @since Version 3.0.0
  1135. */
  1136. __TASK_INLINE unsigned int getSchedulingOption() { return iOption; }
  1137. /**
  1138. * @brief Set the scheduling option for this task
  1139. *
  1140. * Sets the scheduling behavior option that determines how the task's interval
  1141. * and iterations are managed during execution. This affects when the interval
  1142. * countdown begins and how timing is calculated.
  1143. *
  1144. * Scheduling options:
  1145. * - TASK_SCHEDULE: (Default) Interval countdown starts after OnEnable callback completes
  1146. * - TASK_SCHEDULE_NC: No countdown - interval countdown starts immediately when task is enabled
  1147. * - TASK_INTERVAL: Interval mode - maintains exact intervals by accounting for execution time
  1148. *
  1149. * @param aOption The scheduling option to set (TASK_SCHEDULE, TASK_SCHEDULE_NC, or TASK_INTERVAL)
  1150. *
  1151. * @note This method is only available when _TASK_SCHEDULING_OPTIONS compile-time option is enabled
  1152. * @note The scheduling option can be changed at any time, even when the task is running
  1153. * @warning Using TASK_INTERVAL may cause timing drift if task execution time exceeds the interval
  1154. * @see getSchedulingOption(), TASK_SCHEDULE, TASK_SCHEDULE_NC, TASK_INTERVAL
  1155. * @since Version 3.0.0
  1156. */
  1157. __TASK_INLINE void setSchedulingOption(unsigned int aOption) { iOption = aOption; }
  1158. #endif //_TASK_SCHEDULING_OPTIONS
  1159. #ifdef _TASK_OO_CALLBACKS
  1160. /**
  1161. * @brief Set task parameters (Object-Oriented callbacks)
  1162. * @param aInterval Execution interval in milliseconds (or microseconds)
  1163. * @param aIterations Number of iterations (-1 for infinite)
  1164. * @details Allows dynamic control of task execution parameters in one method call.
  1165. */
  1166. __TASK_INLINE void set(unsigned long aInterval, long aIterations);
  1167. #else
  1168. /**
  1169. * @brief Set task parameters (Function pointer callbacks)
  1170. * @param aInterval Execution interval in milliseconds (or microseconds)
  1171. * @param aIterations Number of iterations (-1 for infinite)
  1172. * @param aCallback Pointer to callback function
  1173. * @param aOnEnable Pointer to OnEnable callback (default = NULL)
  1174. * @param aOnDisable Pointer to OnDisable callback (default = NULL)
  1175. * @details Allows dynamic control of task execution parameters in one method call.
  1176. * OnEnable and OnDisable parameters can be omitted (assigned to NULL).
  1177. */
  1178. __TASK_INLINE void set(unsigned long aInterval, long aIterations, TaskCallback aCallback,TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
  1179. #endif // _TASK_OO_CALLBACKS
  1180. /**
  1181. * @brief Set task execution interval
  1182. * @param aInterval New interval in milliseconds (or microseconds)
  1183. * @details Next execution time calculation takes place after the callback method is called,
  1184. * so new interval will be used immediately by the scheduler. Execution is delayed by the
  1185. * provided interval. If immediate invocation is required, call forceNextIteration() after
  1186. * setting new interval or use setIntervalNoDelay() method.
  1187. */
  1188. __TASK_INLINE void setInterval(unsigned long aInterval);
  1189. /**
  1190. * @brief Set task interval without delay
  1191. * @param aInterval New interval in milliseconds (or microseconds)
  1192. * @param aOption How to handle the interval change (default = TASK_INTERVAL_KEEP)
  1193. * TASK_INTERVAL_KEEP - keep the current delay, new interval will be used after current delay expires
  1194. * TASK_INTERVAL_RECALC - recalculate next execution time based on new interval
  1195. * TASK_INTERVAL_RESET - reset schedule, next execution time and new interval are updated
  1196. * @details Sets new interval and provides options for how to handle the timing change.
  1197. */
  1198. __TASK_INLINE void setIntervalNodelay(unsigned long aInterval, unsigned int aOption = TASK_INTERVAL_KEEP);
  1199. /**
  1200. * @brief Get current task interval
  1201. * @return Current execution interval in milliseconds (or microseconds)
  1202. */
  1203. __TASK_INLINE unsigned long getInterval();
  1204. /**
  1205. * @brief Set number of iterations
  1206. * @param aIterations Number of iterations (-1 for infinite)
  1207. * @details Tasks that ran through all their allocated iterations are disabled.
  1208. * SetIterations() method DOES NOT enable the task. Either enable explicitly,
  1209. * or use restart methods.
  1210. */
  1211. __TASK_INLINE void setIterations(long aIterations);
  1212. /**
  1213. * @brief Get remaining iterations
  1214. * @return Number of remaining iterations
  1215. */
  1216. __TASK_INLINE long getIterations();
  1217. /**
  1218. * @brief Get run counter
  1219. * @return Number of times callback method has been invoked since last enable
  1220. * @details The runCounter value is incremented before callback method is invoked.
  1221. * If a task is checking the runCounter value within its callback method, then
  1222. * the first run value is 1.
  1223. */
  1224. __TASK_INLINE unsigned long getRunCounter();
  1225. #ifdef _TASK_SELF_DESTRUCT
  1226. /**
  1227. * @brief Enable or disable self-destruction for this task
  1228. *
  1229. * When self-destruction is enabled, the task will automatically delete itself
  1230. * from the scheduler after it completes its final iteration. This is useful
  1231. * for one-time or temporary tasks that should clean themselves up automatically.
  1232. *
  1233. * Self-destruction behavior:
  1234. * - Task removes itself from the scheduler when it finishes its last iteration
  1235. * - Applies to tasks with finite iterations (setIterations() > 0)
  1236. * - Does not apply to infinite tasks (TASK_FOREVER iterations)
  1237. * - Task object memory is not freed - only removed from scheduler
  1238. *
  1239. * @param aSelfDestruct True to enable self-destruction, false to disable (default: true)
  1240. *
  1241. * @note This method is only available when _TASK_SELF_DESTRUCT compile-time option is enabled
  1242. * @note Self-destruction only occurs after the task naturally completes its iterations
  1243. * @note Manually disabled tasks will not self-destruct
  1244. * @warning Ensure task object remains valid until self-destruction occurs
  1245. * @see getSelfDestruct(), setIterations(), disable()
  1246. * @since Version 3.0.0
  1247. */
  1248. __TASK_INLINE void setSelfDestruct(bool aSelfDestruct=true) { iStatus.selfdestruct = aSelfDestruct; }
  1249. /**
  1250. * @brief Check if self-destruction is enabled for this task
  1251. *
  1252. * Returns whether the task is configured to automatically remove itself from
  1253. * the scheduler after completing its final iteration.
  1254. *
  1255. * @return bool True if self-destruction is enabled, false otherwise
  1256. *
  1257. * @note This method is only available when _TASK_SELF_DESTRUCT compile-time option is enabled
  1258. * @see setSelfDestruct(), setIterations()
  1259. * @since Version 3.0.0
  1260. */
  1261. __TASK_INLINE bool getSelfDestruct() { return iStatus.selfdestruct; }
  1262. #endif // #ifdef _TASK_SELF_DESTRUCT
  1263. #ifdef _TASK_OO_CALLBACKS
  1264. /**
  1265. * @brief Pure virtual main task execution callback (Object-Oriented mode)
  1266. *
  1267. * This pure virtual method must be implemented by derived classes to define
  1268. * the task's main execution logic. Called by the scheduler when the task
  1269. * is ready to execute based on its timing and iteration settings.
  1270. *
  1271. * @return bool True if the execution was "productive" (performed meaningful work),
  1272. * false if the task was idle. A productive return value prevents
  1273. * the scheduler from entering sleep mode on the next idle cycle,
  1274. * optimizing power management for active tasks.
  1275. *
  1276. * @note Only available when _TASK_OO_CALLBACKS compile-time option is enabled
  1277. * @note This is a pure virtual function - derived classes MUST implement it
  1278. * @note Return value affects power management in _TASK_SLEEP_ON_IDLE_RUN mode
  1279. * @see _TASK_OO_CALLBACKS, _TASK_SLEEP_ON_IDLE_RUN
  1280. * @since Version 3.0.0
  1281. *
  1282. * @par Example:
  1283. * @code
  1284. * class MyTask : public Task {
  1285. * public:
  1286. * bool Callback() override {
  1287. * // Perform task work
  1288. * Serial.println("Task executing");
  1289. * return true; // Productive execution
  1290. * }
  1291. * };
  1292. * @endcode
  1293. */
  1294. virtual __TASK_INLINE bool Callback() =0;
  1295. /**
  1296. * @brief Virtual task enable lifecycle callback (Object-Oriented mode)
  1297. *
  1298. * Called when the task transitions from disabled to enabled state. Allows
  1299. * derived classes to implement custom initialization logic, resource allocation,
  1300. * or conditional enabling based on system state.
  1301. *
  1302. * @return bool True to allow the task to be enabled, false to prevent enabling.
  1303. * Returning false keeps the task disabled despite the enable request.
  1304. *
  1305. * @note Only available when _TASK_OO_CALLBACKS compile-time option is enabled
  1306. * @note Default implementation returns true (allow enabling)
  1307. * @note Called synchronously during enable() operation
  1308. * @note Conditional enabling useful for resource-dependent tasks
  1309. * @see _TASK_OO_CALLBACKS, enable(), OnDisable()
  1310. * @since Version 3.0.0
  1311. *
  1312. * @par Example:
  1313. * @code
  1314. * class ConditionalTask : public Task {
  1315. * public:
  1316. * bool OnEnable() override {
  1317. * if (systemReady()) {
  1318. * initializeResources();
  1319. * return true; // Allow enabling
  1320. * }
  1321. * return false; // Prevent enabling
  1322. * }
  1323. * };
  1324. * @endcode
  1325. */
  1326. virtual __TASK_INLINE bool OnEnable();
  1327. /**
  1328. * @brief Virtual task disable lifecycle callback (Object-Oriented mode)
  1329. *
  1330. * Called when the task transitions from enabled to disabled state. Allows
  1331. * derived classes to implement custom cleanup logic, resource deallocation,
  1332. * or state preservation when the task is deactivated.
  1333. *
  1334. * @note Only available when _TASK_OO_CALLBACKS compile-time option is enabled
  1335. * @note Called synchronously during disable() operation
  1336. * @note Called during automatic disable (iteration completion, errors)
  1337. * @note Default implementation performs no action
  1338. * @see _TASK_OO_CALLBACKS, disable(), OnEnable()
  1339. * @since Version 3.0.0
  1340. *
  1341. * @par Example:
  1342. * @code
  1343. * class ResourceTask : public Task {
  1344. * public:
  1345. * void OnDisable() override {
  1346. * cleanupResources();
  1347. * saveState();
  1348. * Serial.println("Task disabled");
  1349. * }
  1350. * };
  1351. * @endcode
  1352. */
  1353. virtual __TASK_INLINE void OnDisable();
  1354. #else
  1355. /**
  1356. * @brief Set the main task execution callback function
  1357. *
  1358. * Assigns a new callback function that will be executed when the task runs.
  1359. * The callback function defines the task's main execution logic and is called
  1360. * by the scheduler when the task is ready to execute.
  1361. *
  1362. * @param aCallback Function pointer to the new callback function.
  1363. * Must have signature: void callbackFunction()
  1364. *
  1365. * @note Only available when _TASK_OO_CALLBACKS is NOT enabled (function pointer mode)
  1366. * @note Callback can be changed dynamically during task execution
  1367. * @note Setting nullptr callback is allowed but will result in no-op execution
  1368. * @see TaskCallback, yield(), yieldOnce()
  1369. * @since Version 1.0.0
  1370. *
  1371. * @par Example:
  1372. * @code
  1373. * void task1Function() {
  1374. * Serial.println("Task 1 executing");
  1375. * }
  1376. *
  1377. * void task2Function() {
  1378. * Serial.println("Task 2 executing");
  1379. * }
  1380. *
  1381. * Task myTask(1000, TASK_FOREVER, task1Function, &scheduler);
  1382. * myTask.setCallback(task2Function); // Switch to different function
  1383. * @endcode
  1384. */
  1385. __TASK_INLINE void setCallback(TaskCallback aCallback) ;
  1386. /**
  1387. * @brief Set the task enable lifecycle callback function
  1388. *
  1389. * Assigns a callback function that will be called when the task transitions
  1390. * from disabled to enabled state. Enables custom initialization logic and
  1391. * conditional enabling based on system conditions.
  1392. *
  1393. * @param aCallback Function pointer to the enable callback function.
  1394. * Must have signature: bool onEnableFunction()
  1395. * Return true to allow enabling, false to prevent it.
  1396. *
  1397. * @note Only available when _TASK_OO_CALLBACKS is NOT enabled (function pointer mode)
  1398. * @note Called synchronously during enable() operation
  1399. * @note Returning false from callback prevents task enabling
  1400. * @note Setting nullptr removes the enable callback
  1401. * @see TaskOnEnable, setOnDisable(), enable()
  1402. * @since Version 2.0.0
  1403. *
  1404. * @par Example:
  1405. * @code
  1406. * bool checkSystemReady() {
  1407. * return digitalRead(READY_PIN) == HIGH;
  1408. * }
  1409. *
  1410. * Task myTask(1000, 10, mainCallback, &scheduler);
  1411. * myTask.setOnEnable(checkSystemReady); // Conditional enabling
  1412. * @endcode
  1413. */
  1414. __TASK_INLINE void setOnEnable(TaskOnEnable aCallback) ;
  1415. /**
  1416. * @brief Set the task disable lifecycle callback function
  1417. *
  1418. * Assigns a callback function that will be called when the task transitions
  1419. * from enabled to disabled state. Enables custom cleanup logic and resource
  1420. * management when the task is deactivated.
  1421. *
  1422. * @param aCallback Function pointer to the disable callback function.
  1423. * Must have signature: void onDisableFunction()
  1424. *
  1425. * @note Only available when _TASK_OO_CALLBACKS is NOT enabled (function pointer mode)
  1426. * @note Called synchronously during disable() operation
  1427. * @note Called during automatic disable (iteration completion, errors)
  1428. * @note Setting nullptr removes the disable callback
  1429. * @see TaskOnDisable, setOnEnable(), disable()
  1430. * @since Version 2.0.0
  1431. *
  1432. * @par Example:
  1433. * @code
  1434. * void cleanupTask() {
  1435. * Serial.println("Task cleaning up");
  1436. * // Release resources, save state, etc.
  1437. * }
  1438. *
  1439. * Task myTask(1000, 5, mainCallback, &scheduler);
  1440. * myTask.setOnDisable(cleanupTask); // Cleanup on disable
  1441. * @endcode
  1442. */
  1443. __TASK_INLINE void setOnDisable(TaskOnDisable aCallback) ;
  1444. /**
  1445. * @brief Permanently switch to a new callback function
  1446. *
  1447. * Changes the task's callback function to the specified new function for all
  1448. * subsequent executions. This enables state machine behavior and multi-phase
  1449. * task processing within a single task object.
  1450. *
  1451. * @param aCallback Function pointer to the new callback function.
  1452. * Must have signature: void newCallbackFunction()
  1453. *
  1454. * @note Only available when _TASK_OO_CALLBACKS is NOT enabled (function pointer mode)
  1455. * @note Change takes effect immediately and is permanent
  1456. * @note All future executions will use the new callback
  1457. * @note Different from yieldOnce() which executes new callback only once
  1458. * @see yieldOnce(), setCallback(), TaskCallback
  1459. * @since Version 2.0.0
  1460. *
  1461. * @par Example:
  1462. * @code
  1463. * void phase1Callback() {
  1464. * Serial.println("Phase 1");
  1465. * // Switch to phase 2 after some condition
  1466. * if (conditionMet()) {
  1467. * myTask.yield(phase2Callback);
  1468. * }
  1469. * }
  1470. *
  1471. * void phase2Callback() {
  1472. * Serial.println("Phase 2");
  1473. * }
  1474. * @endcode
  1475. */
  1476. __TASK_INLINE void yield(TaskCallback aCallback);
  1477. /**
  1478. * @brief Execute a callback function once, then disable the task
  1479. *
  1480. * Switches to the specified callback function for exactly one execution,
  1481. * then automatically disables the task. Useful for one-time completion
  1482. * logic, cleanup operations, or finalization steps.
  1483. *
  1484. * @param aCallback Function pointer to the callback function to execute once.
  1485. * Must have signature: void onceCallbackFunction()
  1486. *
  1487. * @note Only available when _TASK_OO_CALLBACKS is NOT enabled (function pointer mode)
  1488. * @note Task executes the new callback exactly once on next scheduler pass
  1489. * @note Task automatically disables after the single execution
  1490. * @note Original callback is not restored (task becomes inactive)
  1491. * @note Useful for completion handlers and one-shot operations
  1492. * @see yield(), setCallback(), TaskCallback
  1493. * @since Version 2.0.0
  1494. *
  1495. * @par Example:
  1496. * @code
  1497. * void mainCallback() {
  1498. * static int count = 0;
  1499. * Serial.print("Main execution: ");
  1500. * Serial.println(++count);
  1501. *
  1502. * if (count >= 5) {
  1503. * myTask.yieldOnce(finalizationCallback);
  1504. * }
  1505. * }
  1506. *
  1507. * void finalizationCallback() {
  1508. * Serial.println("Task completed - final cleanup");
  1509. * // Task will automatically disable after this
  1510. * }
  1511. * @endcode
  1512. */
  1513. __TASK_INLINE void yieldOnce(TaskCallback aCallback);
  1514. #endif // _TASK_OO_CALLBACKS
  1515. /**
  1516. * @brief Check if this is the first iteration
  1517. * @return true if current pass is (or will be) a first iteration of the task
  1518. */
  1519. __TASK_INLINE bool isFirstIteration() ;
  1520. /**
  1521. * @brief Check if this is the last iteration
  1522. * @return true if current pass is the last iteration (for tasks with limited iterations only)
  1523. */
  1524. __TASK_INLINE bool isLastIteration() ;
  1525. #ifdef _TASK_TIMECRITICAL
  1526. /**
  1527. * @brief Get the execution overrun time in microseconds
  1528. *
  1529. * Returns the amount of time (in microseconds) that the task's execution
  1530. * exceeded its scheduled interval. This measures how much longer the task
  1531. * took to complete compared to its allocated time budget, helping identify
  1532. * timing violations and performance bottlenecks.
  1533. *
  1534. * @return long Overrun time in microseconds. Positive values indicate the task
  1535. * ran longer than its interval, negative values indicate it finished
  1536. * early. Zero indicates the task completed exactly on schedule.
  1537. *
  1538. * @note Only available when _TASK_TIMECRITICAL compile-time option is enabled
  1539. * @note Measured from scheduled execution time to actual completion time
  1540. * @note Useful for real-time system analysis and performance optimization
  1541. * @see getStartDelay(), _TASK_TIMECRITICAL
  1542. * @since Version 3.0.0
  1543. *
  1544. * @par Example:
  1545. * @code
  1546. * void criticalTaskCallback() {
  1547. * // Perform time-critical work
  1548. * performCriticalOperation();
  1549. *
  1550. * // Check if we exceeded our time budget
  1551. * long overrun = myTask.getOverrun();
  1552. * if (overrun > 1000) { // More than 1ms overrun
  1553. * Serial.print("Warning: Task overrun by ");
  1554. * Serial.print(overrun);
  1555. * Serial.println(" microseconds");
  1556. * }
  1557. * }
  1558. * @endcode
  1559. */
  1560. __TASK_INLINE long getOverrun() ;
  1561. /**
  1562. * @brief Get the task start delay in microseconds
  1563. *
  1564. * Returns the amount of time (in microseconds) between when the task was
  1565. * scheduled to start and when it actually began execution. This measures
  1566. * scheduler latency and helps identify system timing accuracy and load issues.
  1567. *
  1568. * @return long Start delay in microseconds. Positive values indicate the task
  1569. * started later than scheduled, negative values indicate it started
  1570. * early. Zero indicates perfect timing accuracy.
  1571. *
  1572. * @note Only available when _TASK_TIMECRITICAL compile-time option is enabled
  1573. * @note Measured from scheduled start time to actual execution start time
  1574. * @note High values may indicate system overload or scheduler inefficiency
  1575. * @see getOverrun(), _TASK_TIMECRITICAL
  1576. * @since Version 3.0.0
  1577. *
  1578. * @par Example:
  1579. * @code
  1580. * void timingAnalysisCallback() {
  1581. * long startDelay = myTask.getStartDelay();
  1582. * long overrun = myTask.getOverrun();
  1583. *
  1584. * Serial.print("Start delay: ");
  1585. * Serial.print(startDelay);
  1586. * Serial.print("us, Overrun: ");
  1587. * Serial.print(overrun);
  1588. * Serial.println("us");
  1589. *
  1590. * if (startDelay > 500) {
  1591. * Serial.println("Warning: High scheduler latency detected");
  1592. * }
  1593. * }
  1594. * @endcode
  1595. */
  1596. __TASK_INLINE long getStartDelay() ;
  1597. #endif // _TASK_TIMECRITICAL
  1598. #ifdef _TASK_STATUS_REQUEST
  1599. /**
  1600. * @brief Wait for a StatusRequest to be signaled, then execute with new parameters
  1601. *
  1602. * Suspends this task until the specified StatusRequest is signaled by another task,
  1603. * then reconfigures this task with new interval and iterations before resuming.
  1604. * Enables sophisticated inter-task communication and coordination patterns.
  1605. *
  1606. * @param aStatusRequest Pointer to StatusRequest object to wait for
  1607. * @param aInterval New execution interval in milliseconds (default: 0 = keep current)
  1608. * @param aIterations New iteration count (default: 1 = single execution)
  1609. *
  1610. * @return bool True if wait was successful and task was reconfigured,
  1611. * false if StatusRequest is invalid or operation failed
  1612. *
  1613. * @note Only available when _TASK_STATUS_REQUEST compile-time option is enabled
  1614. * @note Task becomes inactive until StatusRequest is signaled
  1615. * @note StatusRequest must be signaled by another task's completion
  1616. * @note Interval of 0 keeps current task interval unchanged
  1617. * @see waitForDelayed(), getStatusRequest(), StatusRequest
  1618. * @since Version 3.0.0
  1619. *
  1620. * @par Example:
  1621. * @code
  1622. * Task task1(1000, TASK_FOREVER, task1Callback, &scheduler);
  1623. * Task task2(500, 1, task2Callback, &scheduler);
  1624. *
  1625. * void task1Callback() {
  1626. * // Wait for task2 to complete, then run every 200ms for 5 iterations
  1627. * if (task1.waitFor(task2.getStatusRequest(), 200, 5)) {
  1628. * Serial.println("Task1 resumed after task2 completion");
  1629. * }
  1630. * }
  1631. * @endcode
  1632. */
  1633. __TASK_INLINE bool waitFor(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
  1634. /**
  1635. * @brief Wait for a StatusRequest with delay, then execute with new parameters
  1636. *
  1637. * Similar to waitFor() but introduces an additional delay before the task
  1638. * becomes eligible for execution after the StatusRequest is signaled.
  1639. * Useful for staggered execution and preventing simultaneous task activation.
  1640. *
  1641. * @param aStatusRequest Pointer to StatusRequest object to wait for
  1642. * @param aInterval New execution interval in milliseconds (default: 0 = keep current)
  1643. * @param aIterations New iteration count (default: 1 = single execution)
  1644. *
  1645. * @return bool True if wait was successful and task was reconfigured,
  1646. * false if StatusRequest is invalid or operation failed
  1647. *
  1648. * @note Only available when _TASK_STATUS_REQUEST compile-time option is enabled
  1649. * @note Adds scheduling delay after StatusRequest is signaled
  1650. * @note Prevents immediate execution, allowing for staggered task activation
  1651. * @note Interval of 0 keeps current task interval unchanged
  1652. * @see waitFor(), getStatusRequest(), StatusRequest
  1653. * @since Version 3.0.0
  1654. *
  1655. * @par Example:
  1656. * @code
  1657. * void coordinatorCallback() {
  1658. * // Wait for sensor task, then start processing with 1 second delay
  1659. * if (processingTask.waitForDelayed(sensorTask.getStatusRequest(), 1000, 10)) {
  1660. * Serial.println("Processing will start 1 second after sensor completion");
  1661. * }
  1662. * }
  1663. * @endcode
  1664. */
  1665. __TASK_INLINE bool waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
  1666. /**
  1667. * @brief Get the external StatusRequest object for this task
  1668. *
  1669. * Returns a pointer to the StatusRequest object that other tasks can use
  1670. * to wait for this task's completion. This enables the creation of task
  1671. * dependency chains and sophisticated coordination patterns.
  1672. *
  1673. * @return StatusRequest* Pointer to the task's external StatusRequest object,
  1674. * or nullptr if StatusRequest functionality is not available
  1675. *
  1676. * @note Only available when _TASK_STATUS_REQUEST compile-time option is enabled
  1677. * @note External StatusRequest is signaled when task completes its iterations
  1678. * @note Used by other tasks in waitFor() and waitForDelayed() calls
  1679. * @note Different from getInternalStatusRequest() which is used for internal coordination
  1680. * @see getInternalStatusRequest(), waitFor(), StatusRequest
  1681. * @since Version 3.0.0
  1682. *
  1683. * @par Example:
  1684. * @code
  1685. * Task producerTask(1000, 5, producerCallback, &scheduler);
  1686. * Task consumerTask(100, 1, consumerCallback, &scheduler);
  1687. *
  1688. * void setupTasks() {
  1689. * // Consumer waits for producer to complete
  1690. * StatusRequest* producerStatus = producerTask.getStatusRequest();
  1691. * consumerTask.waitFor(producerStatus, 500, TASK_FOREVER);
  1692. * }
  1693. * @endcode
  1694. */
  1695. __TASK_INLINE StatusRequest* getStatusRequest() ;
  1696. /**
  1697. * @brief Get the internal StatusRequest object for this task
  1698. *
  1699. * Returns a pointer to the internal StatusRequest object used for advanced
  1700. * task coordination patterns within the same task or tightly coupled task groups.
  1701. * Provides finer control over task signaling and coordination mechanisms.
  1702. *
  1703. * @return StatusRequest* Pointer to the task's internal StatusRequest object,
  1704. * or nullptr if StatusRequest functionality is not available
  1705. *
  1706. * @note Only available when _TASK_STATUS_REQUEST compile-time option is enabled
  1707. * @note Internal StatusRequest provides advanced coordination capabilities
  1708. * @note Used for complex task orchestration and state machine patterns
  1709. * @note Separate from external StatusRequest for different coordination levels
  1710. * @see getStatusRequest(), waitFor(), StatusRequest
  1711. * @since Version 3.0.0
  1712. *
  1713. * @par Example:
  1714. * @code
  1715. * void complexCoordinationCallback() {
  1716. * StatusRequest* internalStatus = myTask.getInternalStatusRequest();
  1717. * // Use internal status for advanced coordination
  1718. * otherTask.waitForDelayed(internalStatus, 100, 1);
  1719. * }
  1720. * @endcode
  1721. */
  1722. __TASK_INLINE StatusRequest* getInternalStatusRequest() ;
  1723. #endif // _TASK_STATUS_REQUEST
  1724. #ifdef _TASK_WDT_IDS
  1725. /**
  1726. * @brief Set the watchdog timer ID for this task
  1727. *
  1728. * Assigns a unique identifier to the task for watchdog timer monitoring.
  1729. * The ID is used by external watchdog systems to track task execution
  1730. * and detect hung or malfunctioning tasks in mission-critical applications.
  1731. *
  1732. * @param aID Unique identifier for watchdog monitoring (typically 0-255 range)
  1733. *
  1734. * @note Only available when _TASK_WDT_IDS compile-time option is enabled
  1735. * @note ID should be unique across all tasks in the system
  1736. * @note Used in conjunction with external watchdog hardware/software
  1737. * @note Essential for safety-critical and mission-critical applications
  1738. * @see getId(), setControlPoint(), _TASK_WDT_IDS
  1739. * @since Version 3.0.0
  1740. *
  1741. * @par Example:
  1742. * @code
  1743. * Task criticalTask(1000, TASK_FOREVER, criticalCallback, &scheduler);
  1744. * Task monitorTask(5000, TASK_FOREVER, monitorCallback, &scheduler);
  1745. *
  1746. * void setup() {
  1747. * criticalTask.setId(1); // Critical system task
  1748. * monitorTask.setId(2); // System monitor task
  1749. * }
  1750. *
  1751. * void criticalCallback() {
  1752. * // Reset watchdog for this task ID
  1753. * resetWatchdog(criticalTask.getId());
  1754. * }
  1755. * @endcode
  1756. */
  1757. __TASK_INLINE void setId(unsigned int aID) ;
  1758. /**
  1759. * @brief Get the watchdog timer ID for this task
  1760. *
  1761. * Returns the unique identifier assigned to this task for watchdog monitoring.
  1762. * Used by watchdog systems and monitoring code to identify which task is
  1763. * currently executing or has failed to respond.
  1764. *
  1765. * @return unsigned int The task's watchdog ID, or 0 if no ID has been set
  1766. *
  1767. * @note Only available when _TASK_WDT_IDS compile-time option is enabled
  1768. * @note Returns the ID set by setId(), or 0 for uninitialized tasks
  1769. * @note Used for watchdog reset operations and task identification
  1770. * @see setId(), getControlPoint(), _TASK_WDT_IDS
  1771. * @since Version 3.0.0
  1772. *
  1773. * @par Example:
  1774. * @code
  1775. * void watchdogResetCallback() {
  1776. * unsigned int taskId = myTask.getId();
  1777. * if (taskId > 0) {
  1778. * // Reset watchdog for this specific task
  1779. * resetWatchdogTimer(taskId);
  1780. * Serial.print("Watchdog reset for task ID: ");
  1781. * Serial.println(taskId);
  1782. * }
  1783. * }
  1784. * @endcode
  1785. */
  1786. __TASK_INLINE unsigned int getId() ;
  1787. /**
  1788. * @brief Set the control point identifier for this task
  1789. *
  1790. * Assigns a control point identifier used for fine-grained execution monitoring
  1791. * and debugging. Control points can mark specific execution phases or critical
  1792. * sections within task callbacks for detailed system analysis.
  1793. *
  1794. * @param aPoint Control point identifier (application-defined meaning)
  1795. *
  1796. * @note Only available when _TASK_WDT_IDS compile-time option is enabled
  1797. * @note Control points provide execution phase tracking within tasks
  1798. * @note Used for debugging, profiling, and fine-grained monitoring
  1799. * @note Meaning and usage are application-specific
  1800. * @see getControlPoint(), setId(), _TASK_WDT_IDS
  1801. * @since Version 3.0.0
  1802. *
  1803. * @par Example:
  1804. * @code
  1805. * void complexTaskCallback() {
  1806. * myTask.setControlPoint(1); // Phase 1: Sensor reading
  1807. * readSensors();
  1808. *
  1809. * myTask.setControlPoint(2); // Phase 2: Data processing
  1810. * processData();
  1811. *
  1812. * myTask.setControlPoint(3); // Phase 3: Output generation
  1813. * generateOutput();
  1814. *
  1815. * myTask.setControlPoint(0); // Phase complete
  1816. * }
  1817. * @endcode
  1818. */
  1819. __TASK_INLINE void setControlPoint(unsigned int aPoint) ;
  1820. /**
  1821. * @brief Get the current control point identifier for this task
  1822. *
  1823. * Returns the current control point identifier, indicating which execution
  1824. * phase or critical section the task is currently in or last executed.
  1825. * Useful for debugging hung tasks and execution flow analysis.
  1826. *
  1827. * @return unsigned int Current control point identifier, or 0 if none set
  1828. *
  1829. * @note Only available when _TASK_WDT_IDS compile-time option is enabled
  1830. * @note Returns the most recent control point set by setControlPoint()
  1831. * @note Used for debugging and execution phase identification
  1832. * @note Can help identify where tasks hang or fail
  1833. * @see setControlPoint(), getId(), _TASK_WDT_IDS
  1834. * @since Version 3.0.0
  1835. *
  1836. * @par Example:
  1837. * @code
  1838. * void monitorTaskCallback() {
  1839. * unsigned int controlPoint = criticalTask.getControlPoint();
  1840. * unsigned long lastRun = criticalTask.getRunCounter();
  1841. *
  1842. * if (lastRun == previousRunCount && controlPoint != 0) {
  1843. * Serial.print("Critical task hung at control point: ");
  1844. * Serial.println(controlPoint);
  1845. * // Take corrective action
  1846. * }
  1847. * previousRunCount = lastRun;
  1848. * }
  1849. * @endcode
  1850. */
  1851. __TASK_INLINE unsigned int getControlPoint() ;
  1852. #endif // _TASK_WDT_IDS
  1853. #ifdef _TASK_LTS_POINTER
  1854. /**
  1855. * @brief Set the Local Task Storage (LTS) pointer for this task
  1856. *
  1857. * Assigns a pointer to task-specific data storage that persists across
  1858. * task executions. This enables tasks to maintain state, store working
  1859. * data, or reference external resources without using global variables.
  1860. *
  1861. * @param aPtr Pointer to task-local storage area (any data type)
  1862. *
  1863. * @note Only available when _TASK_LTS_POINTER compile-time option is enabled
  1864. * @note Pointer can reference any data structure or object
  1865. * @note Memory management is application responsibility
  1866. * @note Enables object-oriented patterns and data encapsulation
  1867. * @see getLtsPointer(), _TASK_LTS_POINTER
  1868. * @since Version 3.0.0
  1869. *
  1870. * @par Example:
  1871. * @code
  1872. * struct TaskData {
  1873. * int counter;
  1874. * float average;
  1875. * bool initialized;
  1876. * };
  1877. *
  1878. * TaskData myTaskData = {0, 0.0, false};
  1879. * Task dataTask(1000, TASK_FOREVER, dataCallback, &scheduler);
  1880. *
  1881. * void setup() {
  1882. * dataTask.setLtsPointer(&myTaskData);
  1883. * }
  1884. *
  1885. * void dataCallback() {
  1886. * TaskData* data = (TaskData*)dataTask.getLtsPointer();
  1887. * if (data) {
  1888. * data->counter++;
  1889. * // Use task-specific data
  1890. * }
  1891. * }
  1892. * @endcode
  1893. */
  1894. __TASK_INLINE void setLtsPointer(void *aPtr) ;
  1895. /**
  1896. * @brief Get the Local Task Storage (LTS) pointer for this task
  1897. *
  1898. * Returns the pointer to task-specific data storage previously set with
  1899. * setLtsPointer(). Enables tasks to access their persistent data without
  1900. * relying on global variables or external storage mechanisms.
  1901. *
  1902. * @return void* Pointer to task-local storage, or nullptr if none set
  1903. *
  1904. * @note Only available when _TASK_LTS_POINTER compile-time option is enabled
  1905. * @note Returned pointer must be cast to appropriate data type
  1906. * @note Returns nullptr if no LTS pointer has been set
  1907. * @note Enables clean data encapsulation and object-oriented patterns
  1908. * @see setLtsPointer(), _TASK_LTS_POINTER
  1909. * @since Version 3.0.0
  1910. *
  1911. * @par Example:
  1912. * @code
  1913. * struct SensorData {
  1914. * float temperature;
  1915. * float humidity;
  1916. * unsigned long lastReading;
  1917. * };
  1918. *
  1919. * void sensorCallback() {
  1920. * SensorData* data = (SensorData*)sensorTask.getLtsPointer();
  1921. * if (data) {
  1922. * data->temperature = readTemperature();
  1923. * data->humidity = readHumidity();
  1924. * data->lastReading = millis();
  1925. *
  1926. * Serial.print("Temp: ");
  1927. * Serial.print(data->temperature);
  1928. * Serial.print("°C, Humidity: ");
  1929. * Serial.print(data->humidity);
  1930. * Serial.println("%");
  1931. * }
  1932. * }
  1933. * @endcode
  1934. */
  1935. __TASK_INLINE void* getLtsPointer() ;
  1936. #endif // _TASK_LTS_POINTER
  1937. #ifdef _TASK_EXPOSE_CHAIN
  1938. /**
  1939. * @brief Get pointer to the previous task in the scheduler's task chain
  1940. *
  1941. * Returns a pointer to the task that precedes this task in the scheduler's
  1942. * internal linked list. This enables task chain traversal, debugging, and
  1943. * advanced task management operations for custom scheduler behaviors.
  1944. *
  1945. * @return Task* Pointer to the previous task in the chain, or nullptr if:
  1946. * - This is the first task in the chain
  1947. * - Task is not currently registered with a scheduler
  1948. * - Task chain is empty
  1949. *
  1950. * @note Only available when _TASK_EXPOSE_CHAIN compile-time option is enabled
  1951. * @note Exposes internal scheduler data structure for advanced operations
  1952. * @note Chain order may not correlate with execution order (depends on timing)
  1953. * @note Useful for debugging, custom algorithms, and chain analysis
  1954. * @warning Direct chain manipulation can corrupt scheduler state
  1955. * @see getNextTask(), _TASK_EXPOSE_CHAIN
  1956. * @since Version 3.0.0
  1957. *
  1958. * @par Example:
  1959. * @code
  1960. * void analyzeTaskChain(Task& startTask) {
  1961. * Task* current = &startTask;
  1962. * int position = 0;
  1963. *
  1964. * // Walk backwards through the chain
  1965. * while (current->getPreviousTask() != nullptr) {
  1966. * current = current->getPreviousTask();
  1967. * position++;
  1968. * }
  1969. *
  1970. * Serial.print("Task is at position ");
  1971. * Serial.print(position);
  1972. * Serial.println(" from chain start");
  1973. * }
  1974. *
  1975. * void debugTaskChain(Scheduler& scheduler) {
  1976. * // Find chain relationships for debugging
  1977. * Serial.println("Task Chain Analysis:");
  1978. * // Implementation would traverse and analyze the chain
  1979. * }
  1980. * @endcode
  1981. */
  1982. __TASK_INLINE Task* getPreviousTask() { return iPrev; };
  1983. /**
  1984. * @brief Get pointer to the next task in the scheduler's task chain
  1985. *
  1986. * Returns a pointer to the task that follows this task in the scheduler's
  1987. * internal linked list. This enables forward chain traversal, task enumeration,
  1988. * and advanced scheduler analysis for custom task management operations.
  1989. *
  1990. * @return Task* Pointer to the next task in the chain, or nullptr if:
  1991. * - This is the last task in the chain
  1992. * - Task is not currently registered with a scheduler
  1993. * - Task chain is empty
  1994. *
  1995. * @note Only available when _TASK_EXPOSE_CHAIN compile-time option is enabled
  1996. * @note Exposes internal scheduler data structure for advanced operations
  1997. * @note Chain order is registration order, not execution priority
  1998. * @note Useful for iteration, monitoring, and custom scheduler algorithms
  1999. * @warning Direct chain manipulation can corrupt scheduler state
  2000. * @see getPreviousTask(), _TASK_EXPOSE_CHAIN
  2001. * @since Version 3.0.0
  2002. *
  2003. * @par Example:
  2004. * @code
  2005. * void printAllTasks(Task& firstTask) {
  2006. * Task* current = &firstTask;
  2007. * int taskCount = 0;
  2008. *
  2009. * Serial.println("=== Task Chain Report ===");
  2010. * while (current != nullptr) {
  2011. * taskCount++;
  2012. * Serial.print("Task ");
  2013. * Serial.print(taskCount);
  2014. * Serial.print(": Enabled=");
  2015. * Serial.print(current->isEnabled() ? "YES" : "NO");
  2016. * Serial.print(", Interval=");
  2017. * Serial.print(current->getInterval());
  2018. * Serial.print("ms, Iterations=");
  2019. * Serial.println(current->getIterations());
  2020. *
  2021. * current = current->getNextTask();
  2022. * }
  2023. * Serial.print("Total tasks: ");
  2024. * Serial.println(taskCount);
  2025. * }
  2026. *
  2027. * int countEnabledTasks(Task& anyTask) {
  2028. * // Find start of chain
  2029. * Task* start = &anyTask;
  2030. * while (start->getPreviousTask() != nullptr) {
  2031. * start = start->getPreviousTask();
  2032. * }
  2033. *
  2034. * // Count enabled tasks
  2035. * int enabledCount = 0;
  2036. * Task* current = start;
  2037. * while (current != nullptr) {
  2038. * if (current->isEnabled()) {
  2039. * enabledCount++;
  2040. * }
  2041. * current = current->getNextTask();
  2042. * }
  2043. * return enabledCount;
  2044. * }
  2045. * @endcode
  2046. */
  2047. __TASK_INLINE Task* getNextTask() { return iNext; };
  2048. #endif // _TASK_EXPOSE_CHAIN
  2049. _TASK_SCOPE:
  2050. __TASK_INLINE void reset();
  2051. volatile _task_status iStatus;
  2052. volatile unsigned long iInterval; // execution interval in milliseconds (or microseconds). 0 - immediate
  2053. volatile unsigned long iDelay; // actual delay until next execution (usually equal iInterval)
  2054. volatile unsigned long iPreviousMillis; // previous invocation time (millis). Next invocation = iPreviousMillis + iInterval. Delayed tasks will "catch up"
  2055. #ifdef _TASK_SCHEDULING_OPTIONS
  2056. unsigned int iOption; // scheduling option
  2057. #endif // _TASK_SCHEDULING_OPTIONS
  2058. #ifdef _TASK_TIMECRITICAL
  2059. volatile long iOverrun; // negative if task is "catching up" to it's schedule (next invocation time is already in the past)
  2060. volatile long iStartDelay; // actual execution of the task's callback method was delayed by this number of millis
  2061. #endif // _TASK_TIMECRITICAL
  2062. volatile long iIterations; // number of iterations left. 0 - last iteration. -1 - infinite iterations
  2063. long iSetIterations; // number of iterations originally requested (for restarts)
  2064. unsigned long iRunCounter; // current number of iteration (starting with 1). Resets on enable.
  2065. #ifndef _TASK_OO_CALLBACKS
  2066. TaskCallback iCallback; // pointer to the void callback method
  2067. TaskOnEnable iOnEnable; // pointer to the bool OnEnable callback method
  2068. TaskOnDisable iOnDisable; // pointer to the void OnDisable method
  2069. #endif // _TASK_OO_CALLBACKS
  2070. Task *iPrev, *iNext; // pointers to the previous and next tasks in the chain
  2071. Scheduler *iScheduler; // pointer to the current scheduler
  2072. #ifdef _TASK_STATUS_REQUEST
  2073. StatusRequest *iStatusRequest; // pointer to the status request task is or was waiting on
  2074. StatusRequest iMyStatusRequest; // internal Status request to let other tasks know of completion
  2075. #endif // _TASK_STATUS_REQUEST
  2076. #ifdef _TASK_WDT_IDS
  2077. unsigned int iTaskID; // task ID (for debugging and watchdog identification)
  2078. unsigned int iControlPoint; // current control point within the callback method. Reset to 0 by scheduler at the beginning of each pass
  2079. #endif // _TASK_WDT_IDS
  2080. #ifdef _TASK_LTS_POINTER
  2081. void *iLTS; // pointer to task's local storage. Needs to be recast to appropriate type (usually a struct).
  2082. #endif // _TASK_LTS_POINTER
  2083. #ifdef _TASK_TIMEOUT
  2084. unsigned long iTimeout; // Task overall timeout
  2085. unsigned long iStarttime; // millis at task start time
  2086. #endif // _TASK_TIMEOUT
  2087. };
  2088. /**
  2089. * @class Scheduler
  2090. * @brief Task scheduler for cooperative multitasking
  2091. *
  2092. * @details The Scheduler class manages the execution of tasks in a cooperative multitasking environment.
  2093. * It maintains a chain of tasks and executes them according to their schedules and priorities.
  2094. *
  2095. * Key features:
  2096. * - Cooperative multitasking (non-preemptive)
  2097. * - Task chain management
  2098. * - Priority layer support
  2099. * - Sleep mode support for power saving
  2100. * - Thread safety options
  2101. * - Performance monitoring
  2102. *
  2103. * The scheduler executes Tasks' callback methods in the order the tasks were added to the chain,
  2104. * from first to last. Scheduler stops and exits after processing the chain once in order to allow
  2105. * other statements in the main code of loop() method to run. This is referred to as a "scheduling pass".
  2106. *
  2107. * @note Normally, there is no need to have any other statements in the loop() method other than
  2108. * the Scheduler's execute() method.
  2109. *
  2110. * @see Task, StatusRequest
  2111. */
  2112. class Scheduler {
  2113. friend class Task;
  2114. public:
  2115. /**
  2116. * @brief Default constructor
  2117. * @details Creates task scheduler with default parameters and an empty task queue.
  2118. */
  2119. __TASK_INLINE Scheduler();
  2120. /**
  2121. * @brief Initialize the scheduler
  2122. * @details Initializes the task queue and scheduler parameters. Executed as part of constructor,
  2123. * so doesn't need to be explicitly called after creation.
  2124. *
  2125. * @note By default scheduler is allowed to put processor to IDLE sleep mode. If this behavior
  2126. * was changed via allowSleep() method, init() will NOT reset the sleep parameter.
  2127. */
  2128. __TASK_INLINE void init();
  2129. /**
  2130. * @brief Add task to execution chain
  2131. * @param aTask Reference to task to be added
  2132. * @details Adds task to the execution queue (or chain) of tasks by appending it to the end
  2133. * of the chain. If two tasks are scheduled for execution, the sequence will match the order
  2134. * in which tasks were appended to the chain.
  2135. *
  2136. * @note Currently, changing the execution sequence in a chain dynamically is not supported.
  2137. * If you need to reorder the chain sequence – initialize the scheduler and re-add the tasks
  2138. * in a different order.
  2139. */
  2140. __TASK_INLINE void addTask(Task& aTask);
  2141. /**
  2142. * @brief Delete task from execution chain
  2143. * @param aTask Reference to task to be deleted
  2144. * @details Deletes task from the execution chain. The chain of remaining tasks is linked
  2145. * together. It is not required to delete a task from the chain. A disabled task will not
  2146. * be executed anyway, but you save a few microseconds per scheduling pass by deleting it.
  2147. */
  2148. __TASK_INLINE void deleteTask(Task& aTask);
  2149. /**
  2150. * @brief Pause the scheduler
  2151. * @details Temporarily suspends all task execution. Tasks remain in their current state
  2152. * but will not be executed until resume() is called.
  2153. */
  2154. __TASK_INLINE void pause() { iPaused = true; };
  2155. /**
  2156. * @brief Resume the scheduler
  2157. * @details Resumes task execution after pause().
  2158. */
  2159. __TASK_INLINE void resume() { iPaused = false; };
  2160. /**
  2161. * @brief Enable the scheduler
  2162. * @details Enables the scheduler for task execution.
  2163. */
  2164. __TASK_INLINE void enable() { iEnabled = true; };
  2165. /**
  2166. * @brief Disable the scheduler
  2167. * @details Disables the scheduler, preventing any task execution.
  2168. */
  2169. __TASK_INLINE void disable() { iEnabled = false; };
  2170. #ifdef _TASK_PRIORITY
  2171. /**
  2172. * @brief Disable all tasks (with priority support)
  2173. * @param aRecursive If true (default), disable higher priority tasks as well
  2174. * @details Convenient method to disable majority of tasks.
  2175. */
  2176. __TASK_INLINE void disableAll(bool aRecursive = true);
  2177. /**
  2178. * @brief Enable all tasks (with priority support)
  2179. * @param aRecursive If true (default), enable higher priority tasks as well
  2180. * @details Convenient method to enable majority of tasks.
  2181. */
  2182. __TASK_INLINE void enableAll(bool aRecursive = true);
  2183. /**
  2184. * @brief Set all tasks to start immediately (with priority support)
  2185. * @param aRecursive If true (default), affect higher priority tasks as well
  2186. * @details Sets ALL active tasks to start execution immediately. Should be placed
  2187. * at the end of setup() method to prevent task execution race due to long running
  2188. * setup tasks. Any tasks which should execute after a delay should be explicitly
  2189. * delayed after call to startNow() method.
  2190. */
  2191. __TASK_INLINE void startNow(bool aRecursive = true);
  2192. #else
  2193. /**
  2194. * @brief Disable all tasks
  2195. * @details Convenient method to disable majority of tasks.
  2196. */
  2197. __TASK_INLINE void disableAll();
  2198. /**
  2199. * @brief Enable all tasks
  2200. * @details Convenient method to enable majority of tasks.
  2201. */
  2202. __TASK_INLINE void enableAll();
  2203. /**
  2204. * @brief Set all tasks to start immediately
  2205. * @details Sets ALL active tasks to start execution immediately. Should be placed
  2206. * at the end of setup() method to prevent task execution race due to long running
  2207. * setup tasks.
  2208. */
  2209. __TASK_INLINE void startNow();
  2210. #endif
  2211. /**
  2212. * @brief Execute one scheduling pass
  2213. * @return true if none of the tasks' callback methods was invoked (true = idle run)
  2214. * @details Executes one scheduling pass, including (in case of the base priority scheduler)
  2215. * end-of-pass sleep. This method should be placed inside the loop() method of the sketch.
  2216. * Since execute exits after every pass, you can put additional statements after execute
  2217. * inside the loop().
  2218. *
  2219. * If layered task prioritization is enabled, all higher priority tasks will be evaluated
  2220. * and invoked by the base execute() method. There is no need to call execute() of the
  2221. * higher priority schedulers explicitly.
  2222. *
  2223. * The execute method performs the following steps:
  2224. * 1. Call higher priority scheduler's execute method, if provided
  2225. * 2. Ignore task completely if it is disabled
  2226. * 3. Disable task if it ran out of iterations (calling OnDisable, if necessary)
  2227. * 4. Check if task is waiting on a StatusRequest object, and make appropriate scheduling arrangements
  2228. * 5. Perform necessary timing calculations
  2229. * 6. Invoke task's callback method, if it is time to do so, and one is provided
  2230. * 7. Put microcontroller to sleep (if requested and supported) if none of the tasks were invoked
  2231. *
  2232. * @note Schedule-related calculations are performed prior to task's callback method invocation.
  2233. * This allows tasks to manipulate their runtime parameters (like execution interval) directly.
  2234. */
  2235. __TASK_INLINE bool execute();
  2236. /**
  2237. * @brief Get reference to currently executing task (deprecated)
  2238. * @return Reference to the currently active task
  2239. * @deprecated Use getCurrentTask() instead
  2240. */
  2241. __TASK_INLINE Task& currentTask() ;
  2242. /**
  2243. * @brief Get pointer to currently executing task
  2244. * @return Pointer to the currently active task
  2245. * @details Returns pointer to the task currently executing via execute() loop OR for
  2246. * OnEnable and OnDisable methods, pointer to the task being enabled or disabled.
  2247. * This distinction is important because one task can activate another.
  2248. * Could be used by callback methods to identify which Task invoked this callback method.
  2249. */
  2250. __TASK_INLINE Task* getCurrentTask() ;
  2251. /**
  2252. * @brief Get time until next iteration of a task
  2253. * @param aTask Reference to the task to query
  2254. * @return Number of milliseconds (or microseconds) until next scheduled iteration
  2255. * @details Returns 0 if next iteration is already due (or overdue).
  2256. * Returns -1 if a Task is not active or waiting on an event, and next iteration
  2257. * runtime cannot be determined.
  2258. */
  2259. __TASK_INLINE long timeUntilNextIteration(Task& aTask);
  2260. /**
  2261. * @brief Get number of active tasks
  2262. * @return Number of currently active (enabled) tasks
  2263. */
  2264. __TASK_INLINE unsigned long getActiveTasks() { return iActiveTasks; }
  2265. /**
  2266. * @brief Get total number of tasks
  2267. * @return Total number of tasks in the scheduler
  2268. */
  2269. __TASK_INLINE unsigned long getTotalTasks() { return iTotalTasks; }
  2270. /**
  2271. * @brief Get number of invoked tasks
  2272. * @return Number of tasks that were invoked during the last execute() pass
  2273. */
  2274. __TASK_INLINE unsigned long getInvokedTasks() { return iInvokedTasks; }
  2275. #ifdef _TASK_TICKLESS
  2276. /**
  2277. * @brief Get next run time (tickless mode)
  2278. * @return Next scheduled run time
  2279. * @details Available only when compiled with _TASK_TICKLESS support.
  2280. */
  2281. __TASK_INLINE unsigned long getNextRun() { return iNextRun; }
  2282. #endif
  2283. #ifdef _TASK_SLEEP_ON_IDLE_RUN
  2284. /**
  2285. * @brief Enable or disable sleep mode during idle scheduler cycles
  2286. *
  2287. * Controls whether the scheduler should enter sleep mode when no tasks
  2288. * are ready for execution. Sleep mode reduces power consumption by
  2289. * halting CPU execution until the next task is scheduled to run.
  2290. *
  2291. * @param aState True to enable sleep mode (default), false to disable
  2292. *
  2293. * @note Only available when _TASK_SLEEP_ON_IDLE_RUN compile-time option is enabled
  2294. * @note Sleep is only activated when all tasks return false from their callbacks
  2295. * @note Tasks returning true (productive execution) prevent sleep on next cycle
  2296. * @note Custom sleep method can be set with setSleepMethod()
  2297. * @see setSleepMethod(), _TASK_SLEEP_ON_IDLE_RUN
  2298. * @since Version 3.0.0
  2299. *
  2300. * @par Example:
  2301. * @code
  2302. * Scheduler powerEfficientScheduler;
  2303. *
  2304. * void setup() {
  2305. * // Enable power-saving sleep mode
  2306. * powerEfficientScheduler.allowSleep(true);
  2307. *
  2308. * // Custom sleep implementation
  2309. * powerEfficientScheduler.setSleepMethod(customSleepCallback);
  2310. * }
  2311. *
  2312. * void customSleepCallback(unsigned long aTimeToSleep) {
  2313. * if (aTimeToSleep > 1000) {
  2314. * // Deep sleep for longer periods
  2315. * ESP.deepSleep(aTimeToSleep * 1000); // Convert to microseconds
  2316. * } else {
  2317. * // Light sleep for short periods
  2318. * delay(aTimeToSleep);
  2319. * }
  2320. * }
  2321. * @endcode
  2322. */
  2323. __TASK_INLINE void allowSleep(bool aState = true);
  2324. /**
  2325. * @brief Set custom sleep implementation callback
  2326. *
  2327. * Assigns a custom callback function that will be called when the scheduler
  2328. * enters sleep mode. This allows for platform-specific power management
  2329. * implementations, such as deep sleep modes on ESP32 or low-power modes
  2330. * on Arduino boards.
  2331. *
  2332. * @param aCallback Function pointer to sleep callback with signature:
  2333. * void sleepCallback(unsigned long sleepTime)
  2334. * where sleepTime is in milliseconds
  2335. *
  2336. * @note Only available when _TASK_SLEEP_ON_IDLE_RUN compile-time option is enabled
  2337. * @note Sleep callback receives the calculated sleep duration in milliseconds
  2338. * @note Default implementation uses delay() if no custom callback is set
  2339. * @note Callback should implement appropriate power management for the platform
  2340. * @see allowSleep(), SleepCallback, _TASK_SLEEP_ON_IDLE_RUN
  2341. * @since Version 3.0.0
  2342. *
  2343. * @par Example:
  2344. * @code
  2345. * void arduinoSleep(unsigned long sleepTime) {
  2346. * // Arduino-specific power management
  2347. * if (sleepTime > 100) {
  2348. * // Use watchdog timer for longer sleeps
  2349. * set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  2350. * sleep_enable();
  2351. * sleep_mode();
  2352. * sleep_disable();
  2353. * } else {
  2354. * delay(sleepTime);
  2355. * }
  2356. * }
  2357. *
  2358. * void esp32Sleep(unsigned long sleepTime) {
  2359. * // ESP32-specific power management
  2360. * if (sleepTime > 1000) {
  2361. * esp_sleep_enable_timer_wakeup(sleepTime * 1000ULL);
  2362. * esp_light_sleep_start();
  2363. * } else {
  2364. * delayMicroseconds(sleepTime * 1000);
  2365. * }
  2366. * }
  2367. *
  2368. * scheduler.setSleepMethod(esp32Sleep);
  2369. * @endcode
  2370. */
  2371. __TASK_INLINE void setSleepMethod( SleepCallback aCallback );
  2372. #endif // _TASK_SLEEP_ON_IDLE_RUN
  2373. #ifdef _TASK_LTS_POINTER
  2374. /**
  2375. * @brief Get Local Task Storage pointer of currently executing task
  2376. *
  2377. * Returns the LTS (Local Task Storage) pointer of the task that is
  2378. * currently being executed by the scheduler. This provides access to
  2379. * task-specific data from within the scheduler context or shared utilities.
  2380. *
  2381. * @return void* Pointer to the current task's local storage, or nullptr if:
  2382. * - No task is currently executing
  2383. * - Current task has no LTS pointer set
  2384. * - Called outside of task execution context
  2385. *
  2386. * @note Only available when _TASK_LTS_POINTER compile-time option is enabled
  2387. * @note Must be called from within task execution context for valid results
  2388. * @note Returned pointer must be cast to appropriate data type
  2389. * @note Useful for shared utilities that need access to current task data
  2390. * @see Task::setLtsPointer(), Task::getLtsPointer(), _TASK_LTS_POINTER
  2391. * @since Version 3.0.0
  2392. *
  2393. * @par Example:
  2394. * @code
  2395. * struct TaskData {
  2396. * int sensorValue;
  2397. * float average;
  2398. * bool alertFlag;
  2399. * };
  2400. *
  2401. * void sharedUtilityFunction() {
  2402. * TaskData* currentData = (TaskData*)scheduler.currentLts();
  2403. * if (currentData) {
  2404. * // Access current task's data
  2405. * Serial.print("Current task sensor value: ");
  2406. * Serial.println(currentData->sensorValue);
  2407. *
  2408. * if (currentData->sensorValue > THRESHOLD) {
  2409. * currentData->alertFlag = true;
  2410. * }
  2411. * }
  2412. * }
  2413. *
  2414. * void taskCallback() {
  2415. * // Task-specific work
  2416. * readSensors();
  2417. *
  2418. * // Call shared utility that accesses current task's LTS
  2419. * sharedUtilityFunction();
  2420. * }
  2421. * @endcode
  2422. */
  2423. __TASK_INLINE void* currentLts();
  2424. #endif // _TASK_LTS_POINTER
  2425. #ifdef _TASK_TIMECRITICAL
  2426. /**
  2427. * @brief Check if any task execution overran its allocated time
  2428. *
  2429. * Returns whether any task in the current execution cycle exceeded its
  2430. * scheduled interval time. This provides system-wide timing violation
  2431. * detection for real-time system monitoring and performance analysis.
  2432. *
  2433. * @return bool True if any task overran its allocated time, false otherwise
  2434. *
  2435. * @note Only available when _TASK_TIMECRITICAL compile-time option is enabled
  2436. * @note Checks for timing violations across all tasks in the scheduler
  2437. * @note Useful for system-wide real-time performance monitoring
  2438. * @note Should be checked after each scheduler execution cycle
  2439. * @see Task::getOverrun(), getCpuLoadTotal(), _TASK_TIMECRITICAL
  2440. * @since Version 3.0.0
  2441. *
  2442. * @par Example:
  2443. * @code
  2444. * void loop() {
  2445. * scheduler.execute();
  2446. *
  2447. * // Check for system-wide timing violations
  2448. * if (scheduler.isOverrun()) {
  2449. * Serial.println("WARNING: System overrun detected!");
  2450. *
  2451. * // Log CPU load statistics
  2452. * unsigned long cpuLoad = scheduler.getCpuLoadTotal();
  2453. * Serial.print("CPU Load: ");
  2454. * Serial.print(cpuLoad);
  2455. * Serial.println("%");
  2456. *
  2457. * // Take corrective action
  2458. * if (cpuLoad > 90) {
  2459. * // Reduce system load
  2460. * disableNonCriticalTasks();
  2461. * }
  2462. * }
  2463. * }
  2464. * @endcode
  2465. */
  2466. __TASK_INLINE bool isOverrun();
  2467. /**
  2468. * @brief Reset CPU load measurement counters
  2469. *
  2470. * Resets the internal counters used for CPU load calculation, providing
  2471. * a fresh measurement baseline. This allows for periodic CPU load monitoring
  2472. * and performance analysis over specific time intervals.
  2473. *
  2474. * @note Only available when _TASK_TIMECRITICAL compile-time option is enabled
  2475. * @note Resets both cycle time and idle time counters
  2476. * @note Should be called before starting a new measurement period
  2477. * @note Useful for periodic performance monitoring and load analysis
  2478. * @see getCpuLoadTotal(), getCpuLoadCycle(), getCpuLoadIdle()
  2479. * @since Version 3.0.0
  2480. *
  2481. * @par Example:
  2482. * @code
  2483. * void performanceMonitor() {
  2484. * static unsigned long lastReset = 0;
  2485. * unsigned long now = millis();
  2486. *
  2487. * // Measure CPU load every 10 seconds
  2488. * if (now - lastReset > 10000) {
  2489. * unsigned long cpuLoad = scheduler.getCpuLoadTotal();
  2490. * unsigned long cycleTime = scheduler.getCpuLoadCycle();
  2491. * unsigned long idleTime = scheduler.getCpuLoadIdle();
  2492. *
  2493. * Serial.print("10s Performance Report - CPU Load: ");
  2494. * Serial.print(cpuLoad);
  2495. * Serial.print("%, Cycle: ");
  2496. * Serial.print(cycleTime);
  2497. * Serial.print("us, Idle: ");
  2498. * Serial.print(idleTime);
  2499. * Serial.println("us");
  2500. *
  2501. * // Reset for next measurement period
  2502. * scheduler.cpuLoadReset();
  2503. * lastReset = now;
  2504. * }
  2505. * }
  2506. * @endcode
  2507. */
  2508. __TASK_INLINE void cpuLoadReset();
  2509. /**
  2510. * @brief Get total CPU cycle time in microseconds
  2511. *
  2512. * Returns the cumulative time spent in CPU cycles (active execution)
  2513. * since the last reset. This measures the total processing time used
  2514. * by all tasks and scheduler overhead.
  2515. *
  2516. * @return unsigned long Total CPU cycle time in microseconds
  2517. *
  2518. * @note Only available when _TASK_TIMECRITICAL compile-time option is enabled
  2519. * @note Includes task execution time and scheduler overhead
  2520. * @note Used in conjunction with getCpuLoadIdle() for load calculation
  2521. * @note Accumulates until reset with cpuLoadReset()
  2522. * @see getCpuLoadIdle(), getCpuLoadTotal(), cpuLoadReset()
  2523. * @since Version 3.0.0
  2524. *
  2525. * @par Example:
  2526. * @code
  2527. * void detailedPerformanceAnalysis() {
  2528. * unsigned long cycleTime = scheduler.getCpuLoadCycle();
  2529. * unsigned long idleTime = scheduler.getCpuLoadIdle();
  2530. * unsigned long totalTime = cycleTime + idleTime;
  2531. *
  2532. * if (totalTime > 0) {
  2533. * float cpuUtilization = (float)cycleTime / totalTime * 100.0;
  2534. * float idlePercentage = (float)idleTime / totalTime * 100.0;
  2535. *
  2536. * Serial.print("Detailed Analysis - Active: ");
  2537. * Serial.print(cpuUtilization, 2);
  2538. * Serial.print("%, Idle: ");
  2539. * Serial.print(idlePercentage, 2);
  2540. * Serial.print("%, Total time: ");
  2541. * Serial.print(totalTime);
  2542. * Serial.println("us");
  2543. * }
  2544. * }
  2545. * @endcode
  2546. */
  2547. __TASK_INLINE unsigned long getCpuLoadCycle(){ return iCPUCycle; };
  2548. /**
  2549. * @brief Get total CPU idle time in microseconds
  2550. *
  2551. * Returns the cumulative time spent in idle state (no tasks executing)
  2552. * since the last reset. This measures the total time the CPU was
  2553. * available but not processing tasks.
  2554. *
  2555. * @return unsigned long Total CPU idle time in microseconds
  2556. *
  2557. * @note Only available when _TASK_TIMECRITICAL compile-time option is enabled
  2558. * @note Includes time spent waiting for next task execution
  2559. * @note Used in conjunction with getCpuLoadCycle() for load calculation
  2560. * @note Accumulates until reset with cpuLoadReset()
  2561. * @see getCpuLoadCycle(), getCpuLoadTotal(), cpuLoadReset()
  2562. * @since Version 3.0.0
  2563. *
  2564. * @par Example:
  2565. * @code
  2566. * void powerManagementAnalysis() {
  2567. * unsigned long idleTime = scheduler.getCpuLoadIdle();
  2568. * unsigned long cycleTime = scheduler.getCpuLoadCycle();
  2569. *
  2570. * // Calculate power saving potential
  2571. * if (idleTime > cycleTime) {
  2572. * float powerSavingPotential = (float)idleTime / (idleTime + cycleTime) * 100.0;
  2573. *
  2574. * Serial.print("Power saving potential: ");
  2575. * Serial.print(powerSavingPotential, 1);
  2576. * Serial.println("%");
  2577. *
  2578. * if (powerSavingPotential > 50.0) {
  2579. * Serial.println("Consider enabling sleep mode for better power efficiency");
  2580. * }
  2581. * }
  2582. * }
  2583. * @endcode
  2584. */
  2585. __TASK_INLINE unsigned long getCpuLoadIdle() { return iCPUIdle; };
  2586. /**
  2587. * @brief Get total CPU load percentage
  2588. *
  2589. * Calculates and returns the CPU load as a percentage based on the ratio
  2590. * of active cycle time to total time (cycle + idle). This provides a
  2591. * normalized measure of system utilization for performance monitoring.
  2592. *
  2593. * @return unsigned long CPU load percentage (0-100)
  2594. *
  2595. * @note Only available when _TASK_TIMECRITICAL compile-time option is enabled
  2596. * @note Returns percentage of time spent in active execution vs idle
  2597. * @note Calculation: (cycleTime / (cycleTime + idleTime)) * 100
  2598. * @note Returns 0 if no measurements have been taken
  2599. * @see getCpuLoadCycle(), getCpuLoadIdle(), cpuLoadReset()
  2600. * @since Version 3.0.0
  2601. *
  2602. * @par Example:
  2603. * @code
  2604. * void systemHealthMonitor() {
  2605. * unsigned long cpuLoad = scheduler.getCpuLoadTotal();
  2606. *
  2607. * // System health thresholds
  2608. * if (cpuLoad > 95) {
  2609. * Serial.println("CRITICAL: CPU load extremely high!");
  2610. * // Emergency measures
  2611. * disableNonEssentialTasks();
  2612. * } else if (cpuLoad > 80) {
  2613. * Serial.println("WARNING: High CPU load detected");
  2614. * // Performance optimization
  2615. * optimizeTaskIntervals();
  2616. * } else if (cpuLoad < 10) {
  2617. * Serial.println("INFO: Low CPU load - power optimization opportunity");
  2618. * // Enable power saving features
  2619. * scheduler.allowSleep(true);
  2620. * }
  2621. *
  2622. * // Log current status
  2623. * Serial.print("Current CPU Load: ");
  2624. * Serial.print(cpuLoad);
  2625. * Serial.println("%");
  2626. * }
  2627. * @endcode
  2628. */
  2629. __TASK_INLINE unsigned long getCpuLoadTotal();
  2630. #endif // _TASK_TIMECRITICAL
  2631. #ifdef _TASK_PRIORITY
  2632. /**
  2633. * @brief Sets a higher priority scheduler for priority-based task scheduling
  2634. *
  2635. * This method establishes a hierarchical relationship between schedulers, allowing
  2636. * the current scheduler to defer execution to a higher priority scheduler when needed.
  2637. * This enables multi-level priority scheduling where critical tasks can preempt
  2638. * normal task execution.
  2639. *
  2640. * @param aScheduler Pointer to the higher priority scheduler to associate with this scheduler.
  2641. * Pass nullptr to remove the high priority scheduler association.
  2642. *
  2643. * @note This method is only available when _TASK_PRIORITY compilation option is enabled.
  2644. * @note The high priority scheduler should be executed more frequently than this scheduler
  2645. * to ensure priority-based preemption works correctly.
  2646. * @note Circular priority relationships should be avoided to prevent infinite loops.
  2647. *
  2648. * @see currentScheduler()
  2649. * @see _TASK_PRIORITY
  2650. *
  2651. * Example usage:
  2652. * @code
  2653. * Scheduler highPriorityScheduler;
  2654. * Scheduler normalScheduler;
  2655. *
  2656. * // Set up priority relationship
  2657. * normalScheduler.setHighPriorityScheduler(&highPriorityScheduler);
  2658. *
  2659. * // In main loop, execute high priority first
  2660. * highPriorityScheduler.execute();
  2661. * normalScheduler.execute();
  2662. * @endcode
  2663. */
  2664. __TASK_INLINE void setHighPriorityScheduler(Scheduler* aScheduler);
  2665. /**
  2666. * @brief Returns a reference to the currently executing scheduler
  2667. *
  2668. * This static method provides access to the scheduler that is currently executing tasks.
  2669. * It's primarily used internally by the library to maintain context during task execution
  2670. * and to support priority-based scheduling operations.
  2671. *
  2672. * @return Reference to the currently active scheduler instance
  2673. *
  2674. * @note This method is only available when _TASK_PRIORITY compilation option is enabled.
  2675. * @note This is a static method that can be called without a scheduler instance.
  2676. * @note The returned reference is valid only during task execution context.
  2677. *
  2678. * @warning Do not store the returned reference for long-term use as the current
  2679. * scheduler context changes during execution.
  2680. *
  2681. * @see setHighPriorityScheduler()
  2682. * @see _TASK_PRIORITY
  2683. *
  2684. * Example usage:
  2685. * @code
  2686. * void taskCallback() {
  2687. * // Get reference to the scheduler executing this task
  2688. * Scheduler& currentSched = Scheduler::currentScheduler();
  2689. *
  2690. * // Access scheduler information
  2691. * Serial.print("Active tasks: ");
  2692. * Serial.println(currentSched.size());
  2693. * }
  2694. * @endcode
  2695. */
  2696. __TASK_INLINE static Scheduler& currentScheduler() { return *(iCurrentScheduler); };
  2697. #endif // _TASK_PRIORITY
  2698. #ifdef _TASK_EXPOSE_CHAIN
  2699. /**
  2700. * @brief Returns a pointer to the first task in the scheduler's task chain
  2701. *
  2702. * This method provides direct access to the first task in the internal linked list
  2703. * of tasks managed by this scheduler. It's primarily used for advanced task chain
  2704. * manipulation, debugging, and custom iteration over all tasks.
  2705. *
  2706. * @return Pointer to the first task in the chain, or nullptr if no tasks are registered
  2707. *
  2708. * @note This method is only available when _TASK_EXPOSE_CHAIN compilation option is enabled.
  2709. * @note The returned pointer should be treated as read-only to avoid corrupting the task chain.
  2710. * @note Tasks are stored in a doubly-linked list internally.
  2711. *
  2712. * @warning Direct manipulation of the task chain can lead to undefined behavior.
  2713. * Use the standard addTask() and deleteTask() methods instead.
  2714. *
  2715. * @see getLastTask()
  2716. * @see addTask()
  2717. * @see deleteTask()
  2718. * @see _TASK_EXPOSE_CHAIN
  2719. *
  2720. * Example usage:
  2721. * @code
  2722. * Scheduler ts;
  2723. * Task t1, t2, t3;
  2724. *
  2725. * ts.addTask(t1);
  2726. * ts.addTask(t2);
  2727. * ts.addTask(t3);
  2728. *
  2729. * // Iterate through all tasks
  2730. * Task* current = ts.getFirstTask();
  2731. * while (current != nullptr) {
  2732. * Serial.print("Task ID: ");
  2733. * Serial.println(current->getId());
  2734. * current = current->getNext();
  2735. * }
  2736. * @endcode
  2737. */
  2738. __TASK_INLINE Task* getFirstTask() { return iFirst; };
  2739. /**
  2740. * @brief Returns a pointer to the last task in the scheduler's task chain
  2741. *
  2742. * This method provides direct access to the last task in the internal linked list
  2743. * of tasks managed by this scheduler. It's useful for reverse iteration through
  2744. * the task chain and for advanced task management operations.
  2745. *
  2746. * @return Pointer to the last task in the chain, or nullptr if no tasks are registered
  2747. *
  2748. * @note This method is only available when _TASK_EXPOSE_CHAIN compilation option is enabled.
  2749. * @note The returned pointer should be treated as read-only to avoid corrupting the task chain.
  2750. * @note Tasks are stored in a doubly-linked list internally.
  2751. *
  2752. * @warning Direct manipulation of the task chain can lead to undefined behavior.
  2753. * Use the standard addTask() and deleteTask() methods instead.
  2754. *
  2755. * @see getFirstTask()
  2756. * @see addTask()
  2757. * @see deleteTask()
  2758. * @see _TASK_EXPOSE_CHAIN
  2759. *
  2760. * Example usage:
  2761. * @code
  2762. * Scheduler ts;
  2763. * Task t1, t2, t3;
  2764. *
  2765. * ts.addTask(t1);
  2766. * ts.addTask(t2);
  2767. * ts.addTask(t3);
  2768. *
  2769. * // Iterate through tasks in reverse order
  2770. * Task* current = ts.getLastTask();
  2771. * while (current != nullptr) {
  2772. * Serial.print("Task ID (reverse): ");
  2773. * Serial.println(current->getId());
  2774. * current = current->getPrev();
  2775. * }
  2776. * @endcode
  2777. */
  2778. __TASK_INLINE Task* getLastTask() { return iLast; };
  2779. #endif // _TASK_EXPOSE_CHAIN
  2780. #ifdef _TASK_THREAD_SAFE
  2781. /**
  2782. * @brief Queues a task operation request for thread-safe execution
  2783. *
  2784. * This method places a pre-constructed request structure onto the task request queue
  2785. * for later processing during the next scheduler execution cycle. This provides
  2786. * thread-safe access to task operations from interrupt service routines or other
  2787. * execution contexts.
  2788. *
  2789. * @param aRequest Pointer to a _task_request_t structure containing the operation details.
  2790. * The structure should be properly initialized with the target object,
  2791. * operation type, and parameters.
  2792. *
  2793. * @return true if the request was successfully queued, false if the queue is full
  2794. *
  2795. * @note This method is only available when _TASK_THREAD_SAFE compilation option is enabled.
  2796. * @note The request structure must remain valid until the request is processed.
  2797. * @note Requests are processed in FIFO order during scheduler execution.
  2798. * @note The maximum number of queued requests is limited by the request queue size.
  2799. *
  2800. * @warning The aRequest pointer must point to a valid _task_request_t structure.
  2801. * Invalid pointers will cause undefined behavior.
  2802. *
  2803. * @see requestAction(void*, _task_request_type_t, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)
  2804. * @see processRequests()
  2805. * @see _task_request_t
  2806. * @see _TASK_THREAD_SAFE
  2807. *
  2808. * Example usage:
  2809. * @code
  2810. * _task_request_t request;
  2811. * request.object = &myTask;
  2812. * request.type = TASK_REQUEST_ENABLE;
  2813. * request.param1 = 0;
  2814. * request.param2 = 0;
  2815. * request.param3 = 0;
  2816. * request.param4 = 0;
  2817. * request.param5 = 0;
  2818. *
  2819. * if (ts.requestAction(&request)) {
  2820. * Serial.println("Request queued successfully");
  2821. * } else {
  2822. * Serial.println("Request queue full");
  2823. * }
  2824. * @endcode
  2825. */
  2826. __TASK_INLINE bool requestAction(_task_request_t* aRequest);
  2827. /**
  2828. * @brief Queues a task operation request with individual parameters for thread-safe execution
  2829. *
  2830. * This method creates and queues a task operation request using individual parameters.
  2831. * It provides a convenient interface for thread-safe task operations without requiring
  2832. * manual construction of the request structure.
  2833. *
  2834. * @param aObject Pointer to the target object (Task or Scheduler) for the operation
  2835. * @param aType Type of operation to perform (from _task_request_type_t enum)
  2836. * @param aParam1 First parameter for the operation (interpretation depends on aType)
  2837. * @param aParam2 Second parameter for the operation (interpretation depends on aType)
  2838. * @param aParam3 Third parameter for the operation (interpretation depends on aType)
  2839. * @param aParam4 Fourth parameter for the operation (interpretation depends on aType)
  2840. * @param aParam5 Fifth parameter for the operation (interpretation depends on aType)
  2841. *
  2842. * @return true if the request was successfully queued, false if the queue is full
  2843. *
  2844. * @note This method is only available when _TASK_THREAD_SAFE compilation option is enabled.
  2845. * @note Parameter interpretation varies by operation type - see _task_request_type_t documentation.
  2846. * @note Unused parameters should be set to 0.
  2847. * @note Requests are processed in FIFO order during scheduler execution.
  2848. *
  2849. * @warning The aObject pointer must point to a valid Task or Scheduler instance.
  2850. * Invalid pointers will cause undefined behavior when the request is processed.
  2851. *
  2852. * @see requestAction(_task_request_t*)
  2853. * @see processRequests()
  2854. * @see _task_request_type_t
  2855. * @see _TASK_THREAD_SAFE
  2856. *
  2857. * Example usage:
  2858. * @code
  2859. * // Request to enable a task from an ISR
  2860. * void IRAM_ATTR sensorISR() {
  2861. * ts.requestAction(&sensorTask, TASK_REQUEST_ENABLE, 0, 0, 0, 0, 0);
  2862. * }
  2863. *
  2864. * // Request to restart a task with new interval
  2865. * ts.requestAction(&myTask, TASK_REQUEST_RESTART, 5000, 0, 0, 0, 0); // 5 second interval
  2866. *
  2867. * // Request to set task iterations
  2868. * ts.requestAction(&myTask, TASK_REQUEST_SET_ITERATIONS, 10, 0, 0, 0, 0); // 10 iterations
  2869. * @endcode
  2870. */
  2871. __TASK_INLINE bool requestAction(void* aObject, _task_request_type_t aType, unsigned long aParam1, unsigned long aParam2, unsigned long aParam3, unsigned long aParam4, unsigned long aParam5);
  2872. #endif
  2873. _TASK_SCOPE:
  2874. #ifdef _TASK_THREAD_SAFE
  2875. __TASK_INLINE void processRequests();
  2876. #endif
  2877. Task *iFirst, *iLast, *iCurrent; // pointers to first, last and current tasks in the chain
  2878. volatile bool iPaused, iEnabled;
  2879. unsigned long iActiveTasks;
  2880. unsigned long iTotalTasks;
  2881. unsigned long iInvokedTasks;
  2882. #ifdef _TASK_SLEEP_ON_IDLE_RUN
  2883. bool iAllowSleep; // indication if putting MC to IDLE_SLEEP mode is allowed by the program at this time.
  2884. #endif // _TASK_SLEEP_ON_IDLE_RUN
  2885. #ifdef _TASK_PRIORITY
  2886. Scheduler* iHighPriority; // Pointer to a higher priority scheduler
  2887. #endif // _TASK_PRIORITY
  2888. #ifdef _TASK_TIMECRITICAL
  2889. unsigned long iCPUStart;
  2890. unsigned long iCPUCycle;
  2891. unsigned long iCPUIdle;
  2892. #endif // _TASK_TIMECRITICAL
  2893. #ifdef _TASK_TICKLESS
  2894. unsigned long iNextRun;
  2895. #endif
  2896. };
  2897. #endif /* _TASKSCHEDULERDECLARATIONS_H_ */