TaskScheduler.htm 47 KB

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