TaskScheduler.htm 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
  5. <TITLE></TITLE>
  6. <META NAME="GENERATOR" CONTENT="LibreOffice 3.5 (Linux)">
  7. <META NAME="CREATED" CONTENT="20150206;16300000">
  8. <META NAME="CHANGEDBY" CONTENT="Anatoli Arkhipenko">
  9. <META NAME="CHANGED" CONTENT="20150921;21210000">
  10. <META NAME="Info 1" CONTENT="">
  11. <META NAME="Info 2" CONTENT="">
  12. <META NAME="Info 3" CONTENT="">
  13. <META NAME="Info 4" CONTENT="">
  14. <STYLE TYPE="text/css">
  15. <!--
  16. @page { margin: 0.79in }
  17. P { margin-bottom: 0.08in; direction: ltr; color: #000000; widows: 0; orphans: 0 }
  18. P.western { font-family: "Liberation Serif", "Times New Roman", serif; font-size: 12pt; so-language: en-US }
  19. P.cjk { font-family: "WenQuanYi Micro Hei", "MS Mincho"; font-size: 12pt; so-language: zh-CN }
  20. P.ctl { font-family: "Lohit Hindi", "MS Mincho"; font-size: 12pt; so-language: hi-IN }
  21. -->
  22. </STYLE>
  23. </HEAD>
  24. <BODY LANG="en-US" TEXT="#000000" DIR="LTR">
  25. <P CLASS="western" STYLE="margin-bottom: 0in"><B>Task Scheduler –
  26. cooperative multitasking for Arduino microcontrollers</B></P>
  27. <P CLASS="western" STYLE="margin-bottom: 0in"><B>Version 1.6:
  28. 2015-09-22</B></P>
  29. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  30. </P>
  31. <P CLASS="western" STYLE="margin-bottom: 0in"><B>REQUIREMENT</B>:</P>
  32. <P CLASS="western" STYLE="margin-bottom: 0in">A lightweight
  33. implementation of the task scheduling supporting:</P>
  34. <OL>
  35. <LI><P CLASS="western" STYLE="margin-bottom: 0in">execution period
  36. (n times per second)</P>
  37. <LI><P CLASS="western" STYLE="margin-bottom: 0in">number of
  38. iterations (n times)</P>
  39. <LI><P CLASS="western" STYLE="margin-bottom: 0in">execution of tasks
  40. in predefined sequence</P>
  41. <LI><P CLASS="western" STYLE="margin-bottom: 0in">dynamic change of
  42. the execution parameters for both tasks and execution schedule</P>
  43. <LI><P CLASS="western" STYLE="margin-bottom: 0in">power saving via
  44. entering IDLE sleep mode if no tasks are scheduled to run</P>
  45. </OL>
  46. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  47. </P>
  48. <P CLASS="western" STYLE="margin-bottom: 0in"><B>IDEA</B>:</P>
  49. <P CLASS="western" STYLE="margin-bottom: 0in">“Task” is a
  50. container concept that links together:</P>
  51. <OL>
  52. <LI><P CLASS="western" STYLE="margin-bottom: 0in">Execution interval</P>
  53. <LI><P CLASS="western" STYLE="margin-bottom: 0in">Number of
  54. execution iterations</P>
  55. <LI><P CLASS="western" STYLE="margin-bottom: 0in">A piece of code
  56. performing the task activities (callback function)</P>
  57. </OL>
  58. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  59. </P>
  60. <P CLASS="western" STYLE="margin-bottom: 0in">Tasks are linked into
  61. execution chains, which are processed by the “Scheduler” in the
  62. order they are linked.</P>
  63. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  64. </P>
  65. <P CLASS="western" STYLE="margin-bottom: 0in">Tasks are responsible
  66. for supporting cooperative multitasking by being “good neighbors”,
  67. i.e., running their callback functions in a non-blocking way and
  68. releasing control as soon as possible.
  69. </P>
  70. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  71. </P>
  72. <P CLASS="western" STYLE="margin-bottom: 0in">“Scheduler” is
  73. executing Tasks' callback functions in the order the tasks were added
  74. to the chain, from first to last. Scheduler stops and exists after
  75. processing the chain once in order to allow other statements in the
  76. main code of <B>loop()</B> function to run. This a “scheduling
  77. pass”.</P>
  78. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  79. </P>
  80. <P CLASS="western" STYLE="margin-bottom: 0in">If compiled with
  81. <FONT FACE="Courier New, monospace">_TASK_SLEEP_ON_IDLE_RUN</FONT>
  82. enabled, the scheduler will place processor into IDLE sleep mode (for
  83. approximately 1 ms, as the timer interrupt will wake it up), after
  84. what is determined to be an “idle” pass. An Idle Pass is a pass
  85. through the chain when no Tasks were scheduled to run their callback
  86. functions. This is done to avoid repetitive empty passes through the
  87. chain when no tasks need to be executed. If any of the tasks in the
  88. chain always requires immediate execution (aInterval = 0), then there
  89. will be no end-of-pass delay.</P>
  90. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  91. </P>
  92. <P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Task
  93. Scheduler uses <B>millis()</B> to determine if tasks are ready to be
  94. invoked. Therefore, if you put your device to any “deep” sleep
  95. mode disabling timer interrupts, the <B>millis()</B> count will be
  96. suspended, leading to effective suspension of scheduling. Upon wake
  97. up, active tasks need to be re-enabled, which will effectively reset
  98. their internal time scheduling variables to the new value of
  99. <B>millis(). </B>Time spent in deep sleep mode should be considered
  100. “frozen”, i.e., if a task was scheduled to run in 1 second from
  101. now, and device was put to sleep for 5 minutes, upon wake up, the
  102. task will still be scheduled 1 second from the time of wake up.
  103. Executing <B>enable() </B>function on this tasks will make it run as
  104. soon as possible. This is a concern only for tasks which are required
  105. to run in a truly periodical manner (in absolute time terms).
  106. </P>
  107. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  108. </P>
  109. <P CLASS="western" STYLE="margin-bottom: 0in"><B>COMPILE PARAMETERS:</B></P>
  110. <P CLASS="western" STYLE="margin-bottom: 0in">This library could be
  111. compiled with several options.
  112. </P>
  113. <P CLASS="western" STYLE="margin-bottom: 0in">These parameters must
  114. be defined before inclusion of the library header file into the
  115. sketch.</P>
  116. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  117. </P>
  118. <P CLASS="western" STYLE="margin-bottom: 0in">#define
  119. <B>_TASK_TIMECRITICAL</B></P>
  120. <P CLASS="western" STYLE="margin-bottom: 0in">...will compile the
  121. library with time critical tracking option enabled.</P>
  122. <P CLASS="western" STYLE="margin-bottom: 0in">Time critical option
  123. keeps track where next execution time of the task falls, and makes it
  124. available via API through Task::<B> getOverrun() </B>function. If
  125. <B>getOverrun </B>returns a negative value, this Task’s next
  126. execution time is in the past, and task is behind schedule. This most
  127. probably means that either task’s callback function runtime is too
  128. long, or the execution interval is too short (then schedule is too
  129. aggressive).</P>
  130. <P CLASS="western" STYLE="margin-bottom: 0in">A positive value
  131. indicates that task is on schedule, and callback functions have
  132. enough time to finish before the next scheduled pass.
  133. </P>
  134. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  135. </P>
  136. <P CLASS="western" STYLE="margin-bottom: 0in">#define
  137. <B>_TASK_SLEEP_ON_IDLE_RUN</B></P>
  138. <P CLASS="western" STYLE="margin-bottom: 0in">...will compile the
  139. library with the <B>sleep</B> option enabled (AVR boards only).</P>
  140. <P CLASS="western" STYLE="margin-bottom: 0in">When enabled, scheduler
  141. will put the microcontroller into <B>SLEEP_MODE_IDLE</B> state if
  142. none of the tasks’ callback functions were activated during pass.
  143. <B>IDLE</B> state is interrupted by timers once every 1 ms. Helps
  144. conserve power. Device in SLEEP_MODE_IDLE wakes up to all hardware
  145. and timer interrupts, so scheduling is kept current.</P>
  146. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  147. </P>
  148. <P CLASS="western" STYLE="margin-bottom: 0in"><B>NOTE: above
  149. parameters are DISABLED by default, and need to be explicitly
  150. enabled.</B></P>
  151. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  152. </P>
  153. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  154. </P>
  155. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  156. </P>
  157. <P CLASS="western" STYLE="margin-bottom: 0in"><B>API DOCUMENTATION:</B></P>
  158. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  159. </P>
  160. <P CLASS="western" STYLE="margin-bottom: 0in"><B>TASKS:</B></P>
  161. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  162. </P>
  163. <P CLASS="western" STYLE="margin-bottom: 0in">CREATION:</P>
  164. <P CLASS="western" STYLE="margin-bottom: 0in"><B>Task();</B></P>
  165. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  166. </P>
  167. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Default
  168. constructor.
  169. </P>
  170. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes
  171. no parameters and creates a task that could be scheduled to run at
  172. every scheduling pass indefinitely, but does not have a callback
  173. function defined, so no execution will actually take place.
  174. </P>
  175. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">All
  176. tasks are created <B>disabled</B> by default.</P>
  177. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  178. </P>
  179. <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
  180. <B>Task(unsigned long aInterval, long aIterations, void
  181. (*aCallback)(), Scheduler* aScheduler, bool aEnable);</B></P>
  182. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  183. </P>
  184. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Constructor
  185. with parameters.
  186. </P>
  187. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Creates
  188. a task that is scheduled to run every &lt;aInterval&gt; milliseconds,
  189. &lt;aIterations&gt; times, executing &lt;aCallback&gt; function on
  190. every pass.
  191. </P>
  192. <OL>
  193. <LI><P CLASS="western" STYLE="margin-bottom: 0in">aInterval is in
  194. milliseconds</P>
  195. <LI><P CLASS="western" STYLE="margin-bottom: 0in">aIteration in
  196. number of times, -1 for indefinite execution<BR><B>Note: </B>Tasks
  197. do not remember the number of iteration set initially. After the
  198. iterations are done, internal iteration counter is 0. If you need to
  199. perform another set of iterations, you need to set the number of
  200. iterations again. <BR><B>Note: </B>Tasks which performed all their
  201. iterations remain active.
  202. </P>
  203. <LI><P CLASS="western" STYLE="margin-bottom: 0in">aCallback is a
  204. pointer to a void function without parameters</P>
  205. <LI><P CLASS="western" STYLE="margin-bottom: 0in">aScheduler –
  206. <B>optional</B> reference to existing scheduler. If supplied (not
  207. NULL) this task will be appended to the task chain of the current
  208. scheduler). <B>Default=NULL</B></P>
  209. <LI><P CLASS="western" STYLE="margin-bottom: 0in">aEnable –
  210. <B>optional</B>. Value of <B>true </B>will create task enabled.
  211. <B>Default = false</B></P>
  212. </OL>
  213. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  214. </P>
  215. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">All
  216. tasks are created <B>disabled</B> by default (unless aEnable = true).
  217. You have to explicitly enable the task for execution.</P>
  218. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enabled
  219. task is scheduled for execution immediately. Enable tasks with delay
  220. (standard execution interval or specific execution interval) in order
  221. to defer first run of the task.</P>
  222. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  223. </P>
  224. <P CLASS="western" STYLE="margin-bottom: 0in"><B>INFORMATION</B></P>
  225. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">The
  226. following 3 “getter” functions return task status
  227. (enabled/disabled), execution interval in milliseconds, number of
  228. <I><B>remaining</B></I> iterations.
  229. </P>
  230. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  231. </P>
  232. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>bool
  233. isEnabled() </B>
  234. </P>
  235. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>unsigned
  236. long getInterval()</B></P>
  237. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>long
  238. getIterations() </B>
  239. </P>
  240. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  241. </P>
  242. <P CLASS="western" STYLE="margin-bottom: 0in"><B>long getOverrun()</B></P>
  243. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
  244. library is compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
  245. enabled, tasks are monitored for “long running” scenario. A “long
  246. running” task is a task that does not finish processing its
  247. callback functions quickly, and thus creates a situation for itself
  248. and other tasks where they don't run on a scheduled interval, but
  249. rather “catch up” and are behind. When task scheduler sets the
  250. next execution target time, it adds Task's execution interval to the
  251. previously scheduled execution time:</P>
  252. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> <B>next
  253. execution time = previous execution time + task execution interval</B></P>
  254. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  255. </P>
  256. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
  257. <B>next execution time</B> happens to be already in the past (<B>next
  258. execution time</B> &lt; <B>millis()</B>), then task is considered
  259. <I><B>overrun</B></I>. <B>GetOverrun</B> function returns number of
  260. milliseconds between next execution time and current time. If the
  261. <B>value is negative</B>, the task is overrun by that many
  262. milliseconds.
  263. </P>
  264. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Positive
  265. value indicate number of milliseconds of slack this task has for
  266. execution purposes.
  267. </P>
  268. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  269. </P>
  270. <P CLASS="western" STYLE="margin-bottom: 0in"><B>bool
  271. isFirstIteration()</B></P>
  272. <P CLASS="western" STYLE="margin-bottom: 0in"><B>bool
  273. isLastIteration()</B></P>
  274. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">For
  275. tasks with a defined number of iterations, indicates whether current
  276. pass is a first or a last iteration of the task (respectively).
  277. </P>
  278. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  279. </P>
  280. <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
  281. <B>CONTROL:</B></P>
  282. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  283. </P>
  284. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void enable();</B></P>
  285. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  286. </P>
  287. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables
  288. the task, and schedules it for immediate execution (without delay) at
  289. this or next scheduling pass depending on when the task was enabled.
  290. Scheduler will execute the next pass without any delay because there
  291. is a task which was enabled and requires execution.
  292. </P>
  293. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  294. </P>
  295. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void delay();</B></P>
  296. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  297. </P>
  298. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Schedules
  299. the task for execution after a delay (aInterval), but does not change
  300. the enabled/disabled status of the task.
  301. </P>
  302. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  303. </P>
  304. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void
  305. enableDelayed();</B></P>
  306. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  307. </P>
  308. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables
  309. the task, and schedules it for execution after a delay (aInterval).
  310. </P>
  311. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  312. </P>
  313. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void enableDelayed
  314. (unsigned long aDelay);</B></P>
  315. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  316. </P>
  317. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables
  318. the task, and schedules it for execution after a specific delay
  319. (aDelay, which maybe different from aInterval).
  320. </P>
  321. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  322. </P>
  323. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void restart();</B></P>
  324. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  325. </P>
  326. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">For
  327. tasks with limited number of iterations only, <B>restart</B> function
  328. will re-enable the task, set the number of iterations back to when
  329. the task was created and and schedule the task for execution as soon
  330. as possible.</P>
  331. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  332. </P>
  333. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void restartDelayed
  334. (unsigned long aDelay);</B></P>
  335. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  336. </P>
  337. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Same
  338. as <B>restart() </B>function, with the only difference being that
  339. Task is scheduled to run first iteration after a delay = <B>aDelay</B>
  340. milliseconds.</P>
  341. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  342. </P>
  343. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void disable();</B></P>
  344. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  345. </P>
  346. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Disables
  347. the task. Scheduler will not execute this task any longer, even if it
  348. remains in the chain. Task can be later re-enabled for execution.
  349. </P>
  350. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  351. </P>
  352. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void set(unsigned
  353. long aInterval, long aIterations, void (*aCallback)());</B></P>
  354. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  355. </P>
  356. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Allows
  357. dynamic control of all task execution parameters in one function
  358. call.
  359. </P>
  360. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  361. </P>
  362. <P CLASS="western" STYLE="margin-bottom: 0in">Next three “setter”
  363. functions allow changes of individual task execution control
  364. parameters.
  365. </P>
  366. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void
  367. setInterval (unsigned long aInterval) </B>
  368. </P>
  369. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void
  370. setIterations (long aIterations) </B>
  371. </P>
  372. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void
  373. setCallback (void (*aCallback)()) </B>
  374. </P>
  375. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  376. </P>
  377. <P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Next
  378. execution time calculation takes place <B>after</B> the callback
  379. function is called, so new interval will be used immediately by the
  380. scheduler. For the situations when one task is changing the interval
  381. parameter for the other, <B>setInterval</B> function calls <B>delay
  382. </B>explicitly to guarantee schedule change, however it <B>does not
  383. </B>enable the task if task is disabled.</P>
  384. <P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B><SPAN STYLE="font-weight: normal">Tasks
  385. that ran through all their allocated iterations are disabled.
  386. </SPAN><B>SetIterations()</B><SPAN STYLE="font-weight: normal">
  387. method </SPAN><B>DOES NOT</B><SPAN STYLE="font-weight: normal">
  388. enable the task. Either enable explicitly, or use restart methods. </SPAN>
  389. </P>
  390. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  391. </P>
  392. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  393. </P>
  394. <P CLASS="western" STYLE="margin-bottom: 0in"><B>TASK SCHEDULER:</B></P>
  395. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  396. </P>
  397. <P CLASS="western" STYLE="margin-bottom: 0in"><B>CREATION:</B></P>
  398. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  399. </P>
  400. <P CLASS="western" STYLE="margin-bottom: 0in"><B>Scheduler()</B><BR><BR>
  401. </P>
  402. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Default
  403. constructor.
  404. </P>
  405. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes
  406. no parameters. Creates task scheduler with default parameters and an
  407. empty task queue.
  408. </P>
  409. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  410. </P>
  411. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void init()</B></P>
  412. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  413. </P>
  414. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Initializes
  415. the task queue and scheduler parameters, Executed as part of
  416. constructor, so don't need to be explicitly called after creation.</P>
  417. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
  418. </B>be default (if compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
  419. enabled) scheduler is allowed to put processor to IDLE sleep mode. If
  420. this behavior was changed via <B>allowSleep() </B>function, <B>inti()
  421. </B>will <B>NOT</B> reset allow sleep particular parameter.
  422. </P>
  423. <P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void
  424. addTask(Task&amp; aTask)</B></P>
  425. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  426. </P>
  427. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Adds
  428. task aTask to the execution queue (or chain) of tasks by appending it
  429. to the end of the chain. If two tasks are scheduled for execution,
  430. the sequence will match the order tasks are appended to the chain.
  431. However, in reality, due to different timing of task execution, the
  432. actual order will be different.
  433. </P>
  434. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
  435. </B>Currently, changing the execution dynamically is not supported.
  436. </P>
  437. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
  438. you need to reorder the queue – initialize the scheduler and re-add
  439. the tasks in a different order.
  440. </P>
  441. <P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void
  442. deleteTask(Task&amp; aTask)</B></P>
  443. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  444. </P>
  445. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Deletes
  446. task aTask from the execution chain. The chain of remaining tasks is
  447. linked together (i.e</P>
  448. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">if
  449. original task chain is 1 → 2 → 3 → 4, deleting 3 will result in
  450. 1 → 2 → 4).</P>
  451. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
  452. </B>it is not required to delete a task from the chain. A disabled
  453. task will not be executed anyway, but you save a few microseconds per
  454. scheduling pass by deleting it, since it is not even considered for
  455. execution.
  456. </P>
  457. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">An
  458. example of proper use of this function would be running some sort of
  459. <B>initialize</B> task in the chain, and then deleting it from the
  460. chain since it only needs to run once.
  461. </P>
  462. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  463. </P>
  464. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void allowSleep(bool
  465. aState) </B>
  466. </P>
  467. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  468. </P>
  469. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Available
  470. in API only if compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
  471. enabled. Controls whether scheduler is allowed (<B>aState =true</B>),
  472. or not (<B>aState =false</B>) to put processor into IDLE sleep mode
  473. in case not tasks are scheduled to run.</P>
  474. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">The
  475. <B>default</B> behavior of scheduler upon creation is to allow sleep
  476. mode.
  477. </P>
  478. <P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void enableAll()</B></P>
  479. <P CLASS="western" STYLE="margin-bottom: 0in"><B>void disableAll()</B></P>
  480. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  481. </P>
  482. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">enables
  483. and disables (respectively) all tasks in the chain. Convenient if
  484. your need to enable/disable majority of the tasks (i.e. disable all
  485. and then enable one).
  486. </P>
  487. <P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>Task&amp;
  488. currentTask()<BR></B><BR>
  489. </P>
  490. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
  491. reference to the task, currently executing via <B>execute()</B> loop.
  492. Could be used by callback functions to identify which of the
  493. </P>
  494. <P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void execute()</B></P>
  495. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  496. </P>
  497. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Executes
  498. one scheduling pass, including end-of-pass sleep. This function
  499. typically placed inside the <B>loop()</B> function of the sketch.
  500. Since <B>execute</B> exits after every pass, you can put additional
  501. statements after <B>execute</B> inside the <B>loop()</B>
  502. </P>
  503. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  504. </P>
  505. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  506. </P>
  507. <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
  508. <B>IMPLEMENTATION SCENARIOS AND IDEAS:</B></P>
  509. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  510. </P>
  511. <OL>
  512. <LI><P CLASS="western" STYLE="margin-bottom: 0in"><B>EVENT DRIVEN
  513. PROGRAMMING</B></P>
  514. </OL>
  515. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  516. </P>
  517. <P CLASS="western" STYLE="margin-bottom: 0in">Each of the processes
  518. of your application becomes a separate and distinct programming area,
  519. which may or may not interact and control each other.
  520. </P>
  521. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  522. </P>
  523. <P CLASS="western" STYLE="margin-bottom: 0in">Example:
  524. </P>
  525. <P CLASS="western" STYLE="margin-bottom: 0in">In a plant watering
  526. system you need to measure soil humidity, control pump and display
  527. the results</P>
  528. <P CLASS="western" STYLE="margin-bottom: 0in">Each of the areas
  529. becomes a task:</P>
  530. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  531. </P>
  532. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
  533. <B>tMeasure</B> (TMEASURE_INTERVAL*SECOND, -1,
  534. &amp;measureCallback);<BR>Task <B>tWater</B>
  535. (TWATER_INTERVAL*SECOND, RETRIES, &amp;waterCallback);<BR>Task
  536. <B>tDisplay</B> (TDISPLAY_INTERVAL*SECOND, -1, &amp;displayCallback);
  537. <BR></FONT></FONT><BR>
  538. </P>
  539. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Scheduler
  540. </FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2><B>taskManager</B></FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2>;</FONT></FONT><BR><BR>
  541. </P>
  542. <P CLASS="western" STYLE="margin-bottom: 0in">Further, once you turn
  543. on the pump, you keep it running for TWATER_INTERVAL interval and
  544. then turn it off. Turning off a pump is also a task which only needs
  545. to run once for every time the pump is turned on:</P>
  546. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  547. </P>
  548. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
  549. </FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2><B>tWaterOff</B></FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2>
  550. (WATERTIME*SECOND, 1,</FONT></FONT><FONT FACE="Courier New, monospace">
  551. &amp;waterOffCallback);</FONT><BR><BR>
  552. </P>
  553. <P CLASS="western" STYLE="margin-bottom: 0in">Example of the callback
  554. function:</P>
  555. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  556. </P>
  557. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
  558. waterOffCallback() {<BR> motorOff();<BR>
  559. tWater.enableDelayed();<BR>}</FONT></FONT></P>
  560. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  561. </P>
  562. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>or</FONT></FONT></P>
  563. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  564. </P>
  565. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
  566. waterCallback() {<BR> if (tWater.getIterations()) {</FONT></FONT></P>
  567. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
  568. If this is not the last iteration = turn the pump on<BR>
  569. motorOn();<BR> tWaterOff.set(parameters.watertime * SECOND, 1,
  570. &amp;waterOffCallback);<BR> tWaterOff.enableDelayed();<BR>
  571. return;<BR> }</FONT></FONT></P>
  572. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
  573. We could not reach target humidity – something is wrong<BR>
  574. motorOff;<BR> taskManager.disableAll();<BR> tError.enable();<BR>}</FONT></FONT></P>
  575. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  576. </P>
  577. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Your
  578. sample <B>setup</B>() and <B>loop</B>() (partially) are as follows. </FONT>
  579. </P>
  580. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Note:
  581. </B>please note that tWater is <B>not</B> activated during setup().
  582. It is activated by tMeasure callback once the watering conditions are
  583. met. </FONT>
  584. </P>
  585. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  586. </P>
  587. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"> </FONT><FONT FACE="Courier New, monospace">setup()</FONT></P>
  588. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace">
  589. ...</FONT></P>
  590. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
  591. <FONT FACE="Courier New, monospace">tWater.setIterations(parameters.retries);<BR>
  592. tWaterOff.setInterval(parameters.watertime * SECOND);<BR><BR><BR>
  593. taskManager.init();<BR> taskManager.addTask(tMeasure);<BR>
  594. taskManager.addTask(tDisplay);<BR> taskManager.addTask(tWater);<BR>
  595. taskManager.addTask(tWaterOff);<BR> <BR> tMeasure.enable();<BR>
  596. tDisplay.enable();<BR><BR> currentHumidity =
  597. measureHumidity();<BR>}<BR><BR><BR>void loop ()<BR>{<BR>
  598. taskManager.execute();<BR>}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT><BR>
  599. </P>
  600. <OL START=2>
  601. <LI><P CLASS="western" STYLE="margin-bottom: 0in">“<FONT FACE="Times New Roman, serif"><B>NATIVE”
  602. SUPPORT FOR FINITE STATE MACHINE</B></FONT></P>
  603. </OL>
  604. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  605. </P>
  606. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Define
  607. “states” as callback function or functions. Each callback
  608. function executes activities specific to a “state” and then
  609. “transitions” to the next state by assigning next callback
  610. function to the task. </FONT>
  611. </P>
  612. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Transition
  613. from one state to the next is achieved by setting next callback
  614. function at the end of preceding one. </FONT>
  615. </P>
  616. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Note:
  617. </B>do not call the next callback function. Let the schedule take
  618. care of that during the next pass. (Thus letting other tasks run). </FONT>
  619. </P>
  620. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  621. </P>
  622. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Example:
  623. Blinking LED 2 times a second could be achieved this way</FONT></P>
  624. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  625. </P>
  626. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">Task
  627. tLedBlinker (500, -1, &amp;ledOnCallback);</FONT></P>
  628. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">Scheduler
  629. taskManager;</FONT></P>
  630. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  631. </P>
  632. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">void
  633. ledOnCallback() {</FONT></P>
  634. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> turnLedOn();</FONT></P>
  635. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.setCallback(&amp;ledOffCallback);</FONT></P>
  636. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
  637. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  638. </P>
  639. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">void
  640. ledOffCallback() {</FONT></P>
  641. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> turnLedOff();</FONT></P>
  642. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.setCallback(&amp;ledOnCallback);</FONT></P>
  643. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
  644. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  645. </P>
  646. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">setup()
  647. {</FONT></P>
  648. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> taskManager.init();<BR>
  649. taskManager.addTask(tLedBlinker);</FONT></P>
  650. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> </FONT></P>
  651. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.enable();</FONT></P>
  652. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
  653. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  654. </P>
  655. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">loop
  656. () {</FONT></P>
  657. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> taskManager.execute();</FONT></P>
  658. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT><BR>
  659. </P>
  660. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Obviously
  661. the example is simple, but gives the idea of how the tasks could be
  662. used to go through states.</FONT></P>
  663. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  664. </P>
  665. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  666. </P>
  667. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  668. </P>
  669. <OL START=3>
  670. <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>MULTIPLE
  671. POSSIBLE CALLBACKS FOR TASK</B></FONT></P>
  672. </OL>
  673. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  674. </P>
  675. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">There
  676. may be a need to select an option for callback function based on
  677. certain criteria, or randomly. </FONT>
  678. </P>
  679. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">You
  680. can achieve that by defining an array of callback function pointers
  681. and selecting one based on the criteria you need. </FONT>
  682. </P>
  683. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Example:
  684. when a robot detects an obstacle, it may go left, right backwards,
  685. etc. Each of the “directions” or “behaviors” are represented
  686. by a different callback function. </FONT>
  687. </P>
  688. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  689. </P>
  690. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Another
  691. example of using multiple callbacks:</FONT></P>
  692. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">You
  693. may need to “initialize” variables for a particular task.</FONT></P>
  694. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">In
  695. this case, define a tasks with two callbacks:</FONT></P>
  696. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  697. </P>
  698. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
  699. <B>tWork</B> (T_INTERVAL, -1, &amp;workCallbackInit);</FONT></FONT></P>
  700. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">…</P>
  701. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  702. </P>
  703. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
  704. workCallbackInit() {</FONT></FONT></P>
  705. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
  706. do your initializationstuff here</FONT></FONT></P>
  707. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> </FONT></FONT></P>
  708. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
  709. finally assigne the main callback function </FONT></FONT>
  710. </P>
  711. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.setCallback(&amp;workCallback);</FONT></FONT></P>
  712. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
  713. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
  714. </P>
  715. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
  716. workCallback() {</FONT></FONT></P>
  717. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
  718. main callback function</FONT></FONT></P>
  719. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> …</FONT></FONT></P>
  720. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
  721. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  722. </P>
  723. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">The
  724. task will initialize during first execution pass and switch to
  725. “regular” callback execution starting with second pass. There is
  726. a delay between first and second passes of the task (scheduling
  727. period, if defined). In order to execute the second pass immediately
  728. after initialization first pass, change the above code like this:</FONT></P>
  729. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  730. </P>
  731. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
  732. workCallbackInit() {</FONT></FONT></P>
  733. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
  734. do your initializationstuff here</FONT></FONT></P>
  735. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> </FONT></FONT></P>
  736. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
  737. finally assigne the main callback function </FONT></FONT>
  738. </P>
  739. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.setCallback(&amp;workCallback);</FONT></FONT></P>
  740. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.enable();</FONT></FONT></P>
  741. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
  742. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  743. </P>
  744. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">The
  745. task will run initialization first, then immediately second pass, and
  746. then switch to processing at regular intervals starting with a third
  747. pass. </FONT>
  748. </P>
  749. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  750. </P>
  751. <OL START=3>
  752. <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>INTERRUP-DRIVEN
  753. EXECUTION SUPPORT </B></FONT>
  754. </P>
  755. </OL>
  756. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  757. </P>
  758. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">In
  759. case of interrupt-driven program flow, tasks could be scheduled to
  760. run once to request asynchronous execution (request), and then
  761. re-enabled (restarted) again with a different callback function to
  762. process the results. </FONT>
  763. </P>
  764. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  765. </P>
  766. <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Example</B>:
  767. event driven distance calculation for ultrasonic pulses. EchoPin #6
  768. triggers pin change interrupts on rising and falling edges to
  769. determine the length of ultrasonic pulse.</FONT></P>
  770. <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
  771. </P>
  772. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>#include
  773. &lt;DirectIO.h&gt;<BR>#include &lt;TaskScheduler.h&gt;<BR>#include
  774. &lt;PinChangeInt.h&gt;<BR><BR><BR>#define TRIGGERPIN 5<BR>#define
  775. ECHOPIN 6<BR><BR>Output&lt;TRIGGERPIN&gt;
  776. pTrigger;<BR>Input&lt;ECHOPIN&gt; pEcho;<BR><BR>Scheduler
  777. r;<BR><BR>Task tMeasure(1000, -1, &amp;measureCallback);<BR>Task
  778. tDisplay(1000, -1, &amp;displayCallback);<BR>Task tPing(0, 1,
  779. &amp;pingCalcCallback);<BR><BR><BR>volatile bool pulseBusy =
  780. false;<BR>volatile bool pulseTimeout = false;<BR>volatile unsigned
  781. long pulseStart = 0;<BR>volatile unsigned long pulseStop =
  782. 0;<BR>volatile unsigned long pingDistance = 0;<BR><BR><BR>void
  783. pingTrigger(unsigned long aTimeout) {<BR> if (pulseBusy) return; //
  784. do not trigger if in the middle of a pulse<BR> if (pEcho == HIGH)
  785. return; // do not trigger if ECHO pin is high<BR> <BR> pulseBusy =
  786. true;<BR> pulseTimeout = false;</FONT></FONT></P>
  787. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2><BR>
  788. pTrigger = LOW;<BR> delayMicroseconds(4);<BR> pTrigger = HIGH;<BR><BR>
  789. tPing.setInterval (aTimeout);<BR><BR> delayMicroseconds(10);<BR>
  790. pTrigger = LOW; <BR></FONT></FONT><BR>
  791. </P>
  792. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
  793. <FONT FACE="Courier New, monospace"><FONT SIZE=2>tPing.restartDelayed();
  794. // timeout countdown starts now<BR></FONT></FONT><BR>
  795. </P>
  796. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
  797. will start the pulse clock on the rising edge of ECHO pin</FONT></FONT></P>
  798. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
  799. <FONT FACE="Courier New, monospace"><FONT SIZE=2>PCintPort::attachInterrupt(ECHOPIN,
  800. &amp;pingStartClock, RISING); <BR>}<BR><BR></FONT></FONT><BR>
  801. </P>
  802. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
  803. Start clock on the <B>rising</B> edge of the ultrasonic pulse<BR>void
  804. pingStartClock() {<BR> pulseStart = micros();<BR>
  805. PCintPort::detachInterrupt(ECHOPIN); // not sure this is necessary<BR>
  806. PCintPort::attachInterrupt(ECHOPIN, &amp;pingStopClock, FALLING); <BR>
  807. tPing.restartDelayed();<BR>}<BR><BR>// Stop clock on the <B>falling</B>
  808. edge of the ultrasonic pulse<BR>void pingStopClock() {<BR> pulseStop
  809. = micros();<BR> PcintPort::detachInterrupt(ECHOPIN);</FONT></FONT></P>
  810. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
  811. <FONT FACE="Courier New, monospace"><FONT SIZE=2>pingDistance =
  812. pulseStop - pulseStart;<BR> pulseBusy = false;<BR> tPing.disable();
  813. // disable timeout<BR>}<BR></FONT></FONT><BR>
  814. </P>
  815. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
  816. Stop clock because of the timeout – the wave did not return<BR>void
  817. pingCalcCallback() {<BR> if (pulseBusy) {<BR> pingStopClock();<BR>
  818. }<BR> pulseTimeout = true;<BR>}<BR><BR><BR><BR>// Initial measure
  819. callback sets the trigger<BR>void measureCallback() {<BR> if
  820. (pulseBusy) { // already measuring, try again<BR>
  821. tMeasure.enable();<BR> return;<BR> }<BR> pingTrigger(30); // 30
  822. milliseconds or max range of ~5.1 meters<BR>
  823. tMeasure.setCallback(&amp;measureCallbackWait);<BR>}<BR></FONT></FONT><BR>
  824. </P>
  825. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
  826. Wait for the measurement to <BR>void measureCallbackWait() {<BR> if
  827. (pulseBusy) return;<BR> tMeasure.setCallback(&amp;measureCallback);
  828. <BR>}<BR><BR><BR>bool state = true;<BR><BR>void displayCallback() {<BR>
  829. char d[256];<BR> <BR> unsigned long cm = pingDistance * 17 / 100;
  830. // cm<BR> <BR> snprintf(d, 256, &quot;pulseStart =
  831. %8lu\tpulseStop=%8lu\tdistance, cm=%8lu&quot;, pulseStart, pulseStop,
  832. cm);<BR> Serial.println(d);<BR> <BR>}<BR><BR>void setup() {<BR> //
  833. put your setup code here, to run once:<BR> <BR>
  834. Serial.begin(115200);<BR> <BR><BR> pTrigger = LOW;<BR> pEcho =
  835. LOW;<BR> <BR> r.init();<BR> r.addTask(tDisplay);<BR>
  836. r.addTask(tMeasure);<BR> r.addTask(tPing);<BR> <BR>
  837. r.enableAll();<BR> tPing.disable();<BR>}<BR><BR>void loop() {<BR>
  838. // put your main code here, to run repeatedly:<BR> r.execute();<BR>}<BR></FONT></FONT><BR>
  839. </P>
  840. </BODY>
  841. </HTML>