|
@@ -1,1271 +1,841 @@
|
|
|
-<html>
|
|
|
|
|
-
|
|
|
|
|
-<head>
|
|
|
|
|
-<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
|
|
|
|
|
-<meta name=Generator content="Microsoft Word 14 (filtered)">
|
|
|
|
|
-<style>
|
|
|
|
|
-<!--
|
|
|
|
|
- /* Font Definitions */
|
|
|
|
|
- @font-face
|
|
|
|
|
- {font-family:"Liberation Serif";}
|
|
|
|
|
-@font-face
|
|
|
|
|
- {font-family:OpenSymbol;}
|
|
|
|
|
-@font-face
|
|
|
|
|
- {font-family:"Liberation Sans";}
|
|
|
|
|
- /* Style Definitions */
|
|
|
|
|
- p.MsoNormal, li.MsoNormal, div.MsoNormal
|
|
|
|
|
- {margin:0in;
|
|
|
|
|
- margin-bottom:.0001pt;
|
|
|
|
|
- font-size:12.0pt;
|
|
|
|
|
- font-family:"Liberation Serif";}
|
|
|
|
|
-p.MsoCaption, li.MsoCaption, div.MsoCaption
|
|
|
|
|
- {margin-top:6.0pt;
|
|
|
|
|
- margin-right:0in;
|
|
|
|
|
- margin-bottom:6.0pt;
|
|
|
|
|
- margin-left:0in;
|
|
|
|
|
- font-size:12.0pt;
|
|
|
|
|
- font-family:"Liberation Serif";
|
|
|
|
|
- font-style:italic;}
|
|
|
|
|
-p.MsoList, li.MsoList, div.MsoList
|
|
|
|
|
- {margin-top:0in;
|
|
|
|
|
- margin-right:0in;
|
|
|
|
|
- margin-bottom:6.0pt;
|
|
|
|
|
- margin-left:0in;
|
|
|
|
|
- font-size:12.0pt;
|
|
|
|
|
- font-family:"Liberation Serif";}
|
|
|
|
|
-p.MsoBodyText, li.MsoBodyText, div.MsoBodyText
|
|
|
|
|
- {mso-style-link:"Body Text Char";
|
|
|
|
|
- margin-top:0in;
|
|
|
|
|
- margin-right:0in;
|
|
|
|
|
- margin-bottom:6.0pt;
|
|
|
|
|
- margin-left:0in;
|
|
|
|
|
- font-size:12.0pt;
|
|
|
|
|
- font-family:"Liberation Serif";}
|
|
|
|
|
-span.BodyTextChar
|
|
|
|
|
- {mso-style-name:"Body Text Char";
|
|
|
|
|
- mso-style-link:"Body Text";
|
|
|
|
|
- font-family:"Liberation Serif";}
|
|
|
|
|
-p.Heading, li.Heading, div.Heading
|
|
|
|
|
- {mso-style-name:Heading;
|
|
|
|
|
- margin-top:12.0pt;
|
|
|
|
|
- margin-right:0in;
|
|
|
|
|
- margin-bottom:6.0pt;
|
|
|
|
|
- margin-left:0in;
|
|
|
|
|
- page-break-after:avoid;
|
|
|
|
|
- font-size:14.0pt;
|
|
|
|
|
- font-family:"Liberation Sans";}
|
|
|
|
|
-p.Index, li.Index, div.Index
|
|
|
|
|
- {mso-style-name:Index;
|
|
|
|
|
- margin:0in;
|
|
|
|
|
- margin-bottom:.0001pt;
|
|
|
|
|
- font-size:12.0pt;
|
|
|
|
|
- font-family:"Liberation Serif";}
|
|
|
|
|
-span.WW8Num1z0
|
|
|
|
|
- {mso-style-name:WW8Num1z0;}
|
|
|
|
|
-span.WW8Num1z1
|
|
|
|
|
- {mso-style-name:WW8Num1z1;}
|
|
|
|
|
-span.WW8Num1z2
|
|
|
|
|
- {mso-style-name:WW8Num1z2;}
|
|
|
|
|
-span.WW8Num1z3
|
|
|
|
|
- {mso-style-name:WW8Num1z3;}
|
|
|
|
|
-span.WW8Num1z4
|
|
|
|
|
- {mso-style-name:WW8Num1z4;}
|
|
|
|
|
-span.WW8Num1z5
|
|
|
|
|
- {mso-style-name:WW8Num1z5;}
|
|
|
|
|
-span.WW8Num1z6
|
|
|
|
|
- {mso-style-name:WW8Num1z6;}
|
|
|
|
|
-span.WW8Num1z7
|
|
|
|
|
- {mso-style-name:WW8Num1z7;}
|
|
|
|
|
-span.WW8Num1z8
|
|
|
|
|
- {mso-style-name:WW8Num1z8;}
|
|
|
|
|
-span.WW8Num2z0
|
|
|
|
|
- {mso-style-name:WW8Num2z0;}
|
|
|
|
|
-span.WW8Num2z1
|
|
|
|
|
- {mso-style-name:WW8Num2z1;}
|
|
|
|
|
-span.WW8Num2z2
|
|
|
|
|
- {mso-style-name:WW8Num2z2;}
|
|
|
|
|
-span.WW8Num2z3
|
|
|
|
|
- {mso-style-name:WW8Num2z3;}
|
|
|
|
|
-span.WW8Num2z4
|
|
|
|
|
- {mso-style-name:WW8Num2z4;}
|
|
|
|
|
-span.WW8Num2z5
|
|
|
|
|
- {mso-style-name:WW8Num2z5;}
|
|
|
|
|
-span.WW8Num2z6
|
|
|
|
|
- {mso-style-name:WW8Num2z6;}
|
|
|
|
|
-span.WW8Num2z7
|
|
|
|
|
- {mso-style-name:WW8Num2z7;}
|
|
|
|
|
-span.WW8Num2z8
|
|
|
|
|
- {mso-style-name:WW8Num2z8;}
|
|
|
|
|
-span.WW8Num3z0
|
|
|
|
|
- {mso-style-name:WW8Num3z0;
|
|
|
|
|
- font-weight:normal;}
|
|
|
|
|
-span.WW8Num3z1
|
|
|
|
|
- {mso-style-name:WW8Num3z1;}
|
|
|
|
|
-span.WW8Num3z2
|
|
|
|
|
- {mso-style-name:WW8Num3z2;}
|
|
|
|
|
-span.WW8Num3z3
|
|
|
|
|
- {mso-style-name:WW8Num3z3;}
|
|
|
|
|
-span.WW8Num3z4
|
|
|
|
|
- {mso-style-name:WW8Num3z4;}
|
|
|
|
|
-span.WW8Num3z5
|
|
|
|
|
- {mso-style-name:WW8Num3z5;}
|
|
|
|
|
-span.WW8Num3z6
|
|
|
|
|
- {mso-style-name:WW8Num3z6;}
|
|
|
|
|
-span.WW8Num3z7
|
|
|
|
|
- {mso-style-name:WW8Num3z7;}
|
|
|
|
|
-span.WW8Num3z8
|
|
|
|
|
- {mso-style-name:WW8Num3z8;}
|
|
|
|
|
-span.WW8Num4z0
|
|
|
|
|
- {mso-style-name:WW8Num4z0;}
|
|
|
|
|
-span.WW8Num4z1
|
|
|
|
|
- {mso-style-name:WW8Num4z1;}
|
|
|
|
|
-span.WW8Num4z2
|
|
|
|
|
- {mso-style-name:WW8Num4z2;}
|
|
|
|
|
-span.WW8Num4z3
|
|
|
|
|
- {mso-style-name:WW8Num4z3;}
|
|
|
|
|
-span.WW8Num4z4
|
|
|
|
|
- {mso-style-name:WW8Num4z4;}
|
|
|
|
|
-span.WW8Num4z5
|
|
|
|
|
- {mso-style-name:WW8Num4z5;}
|
|
|
|
|
-span.WW8Num4z6
|
|
|
|
|
- {mso-style-name:WW8Num4z6;}
|
|
|
|
|
-span.WW8Num4z7
|
|
|
|
|
- {mso-style-name:WW8Num4z7;}
|
|
|
|
|
-span.WW8Num4z8
|
|
|
|
|
- {mso-style-name:WW8Num4z8;}
|
|
|
|
|
-span.WW8Num5z0
|
|
|
|
|
- {mso-style-name:WW8Num5z0;
|
|
|
|
|
- font-family:"Times New Roman","serif";
|
|
|
|
|
- font-weight:bold;}
|
|
|
|
|
-span.WW8Num5z1
|
|
|
|
|
- {mso-style-name:WW8Num5z1;}
|
|
|
|
|
-span.WW8Num5z2
|
|
|
|
|
- {mso-style-name:WW8Num5z2;}
|
|
|
|
|
-span.WW8Num5z3
|
|
|
|
|
- {mso-style-name:WW8Num5z3;}
|
|
|
|
|
-span.WW8Num5z4
|
|
|
|
|
- {mso-style-name:WW8Num5z4;}
|
|
|
|
|
-span.WW8Num5z5
|
|
|
|
|
- {mso-style-name:WW8Num5z5;}
|
|
|
|
|
-span.WW8Num5z6
|
|
|
|
|
- {mso-style-name:WW8Num5z6;}
|
|
|
|
|
-span.WW8Num5z7
|
|
|
|
|
- {mso-style-name:WW8Num5z7;}
|
|
|
|
|
-span.WW8Num5z8
|
|
|
|
|
- {mso-style-name:WW8Num5z8;}
|
|
|
|
|
-span.WW8Num6z0
|
|
|
|
|
- {mso-style-name:WW8Num6z0;}
|
|
|
|
|
-span.WW8Num6z1
|
|
|
|
|
- {mso-style-name:WW8Num6z1;}
|
|
|
|
|
-span.WW8Num6z2
|
|
|
|
|
- {mso-style-name:WW8Num6z2;}
|
|
|
|
|
-span.WW8Num6z3
|
|
|
|
|
- {mso-style-name:WW8Num6z3;}
|
|
|
|
|
-span.WW8Num6z4
|
|
|
|
|
- {mso-style-name:WW8Num6z4;}
|
|
|
|
|
-span.WW8Num6z5
|
|
|
|
|
- {mso-style-name:WW8Num6z5;}
|
|
|
|
|
-span.WW8Num6z6
|
|
|
|
|
- {mso-style-name:WW8Num6z6;}
|
|
|
|
|
-span.WW8Num6z7
|
|
|
|
|
- {mso-style-name:WW8Num6z7;}
|
|
|
|
|
-span.WW8Num6z8
|
|
|
|
|
- {mso-style-name:WW8Num6z8;}
|
|
|
|
|
-span.WW8Num7z0
|
|
|
|
|
- {mso-style-name:WW8Num7z0;}
|
|
|
|
|
-span.WW8Num7z1
|
|
|
|
|
- {mso-style-name:WW8Num7z1;}
|
|
|
|
|
-span.WW8Num7z2
|
|
|
|
|
- {mso-style-name:WW8Num7z2;}
|
|
|
|
|
-span.WW8Num7z3
|
|
|
|
|
- {mso-style-name:WW8Num7z3;}
|
|
|
|
|
-span.WW8Num7z4
|
|
|
|
|
- {mso-style-name:WW8Num7z4;}
|
|
|
|
|
-span.WW8Num7z5
|
|
|
|
|
- {mso-style-name:WW8Num7z5;}
|
|
|
|
|
-span.WW8Num7z6
|
|
|
|
|
- {mso-style-name:WW8Num7z6;}
|
|
|
|
|
-span.WW8Num7z7
|
|
|
|
|
- {mso-style-name:WW8Num7z7;}
|
|
|
|
|
-span.WW8Num7z8
|
|
|
|
|
- {mso-style-name:WW8Num7z8;}
|
|
|
|
|
-span.WW-DefaultParagraphFont
|
|
|
|
|
- {mso-style-name:"WW-Default Paragraph Font";}
|
|
|
|
|
-span.Absatz-Standardschriftart
|
|
|
|
|
- {mso-style-name:Absatz-Standardschriftart;}
|
|
|
|
|
-span.NumberingSymbols
|
|
|
|
|
- {mso-style-name:"Numbering Symbols";}
|
|
|
|
|
-span.Bullets
|
|
|
|
|
- {mso-style-name:Bullets;
|
|
|
|
|
- font-family:OpenSymbol;}
|
|
|
|
|
-.MsoChpDefault
|
|
|
|
|
- {font-size:10.0pt;}
|
|
|
|
|
-@page WordSection1
|
|
|
|
|
- {size:8.5in 11.0in;
|
|
|
|
|
- margin:56.7pt 56.7pt 56.7pt 56.7pt;}
|
|
|
|
|
-div.WordSection1
|
|
|
|
|
- {page:WordSection1;}
|
|
|
|
|
- /* List Definitions */
|
|
|
|
|
- ol
|
|
|
|
|
- {margin-bottom:0in;}
|
|
|
|
|
-ul
|
|
|
|
|
- {margin-bottom:0in;}
|
|
|
|
|
--->
|
|
|
|
|
-</style>
|
|
|
|
|
-
|
|
|
|
|
-</head>
|
|
|
|
|
-
|
|
|
|
|
-<body bgcolor=white lang=EN-US style='line-break:strict'>
|
|
|
|
|
-
|
|
|
|
|
-<div class=WordSection1>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>Task Scheduler – cooperative multitasking for Arduino microcontrollers</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>Version 1.51: 2015-09-20</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>REQUIREMENT</b>:</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>A lightweight implementation of the task scheduling
|
|
|
|
|
-supporting:</p>
|
|
|
|
|
-
|
|
|
|
|
-<ol style='margin-top:0in' start=1 type=1>
|
|
|
|
|
- <li class=MsoNormal>execution period (n times per second)</li>
|
|
|
|
|
- <li class=MsoNormal>number of iterations (n times)</li>
|
|
|
|
|
- <li class=MsoNormal>execution of tasks in predefined sequence</li>
|
|
|
|
|
- <li class=MsoNormal>dynamic change of the execution parameters for both tasks
|
|
|
|
|
- and execution schedule</li>
|
|
|
|
|
- <li class=MsoNormal>power saving via entering IDLE sleep mode if no tasks are
|
|
|
|
|
- scheduled to run</li>
|
|
|
|
|
-</ol>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>IDEA</b>:</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>“Task” is a container concept that links together:</p>
|
|
|
|
|
-
|
|
|
|
|
-<ol style='margin-top:0in' start=1 type=1>
|
|
|
|
|
- <li class=MsoNormal>Execution interval</li>
|
|
|
|
|
- <li class=MsoNormal>Number of execution iterations</li>
|
|
|
|
|
- <li class=MsoNormal>A piece of code performing the task activities (callback
|
|
|
|
|
- function)</li>
|
|
|
|
|
-</ol>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Tasks are linked into execution chains, which are processed
|
|
|
|
|
-by the “Scheduler” in the order they are linked.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Tasks are responsible for supporting cooperative
|
|
|
|
|
-multitasking by being “good neighbors”, i.e., running their callback functions
|
|
|
|
|
-in a non-blocking way and releasing control as soon as possible. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>“Scheduler” is executing Tasks' callback functions in the
|
|
|
|
|
-order the tasks were added to the chain, from first to last. Scheduler stops
|
|
|
|
|
-and exists after processing the chain once in order to allow other statements
|
|
|
|
|
-in the main code of <b>loop()</b> function to run. This a “scheduling
|
|
|
|
|
-pass”.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>If compiled with <span style='font-family:"Courier New"'>_TASK_SLEEP_ON_IDLE_RUN</span>
|
|
|
|
|
-enabled, the scheduler will place processor into IDLE sleep mode (for
|
|
|
|
|
-approximately 1 ms, as the timer interrupt will wake it up), after what is
|
|
|
|
|
-determined to be an “idle” pass. An Idle Pass is a pass through the chain when
|
|
|
|
|
-no Tasks were scheduled to run their callback functions. This is done to avoid
|
|
|
|
|
-repetitive empty passes through the chain when no tasks need to be executed. If
|
|
|
|
|
-any of the tasks in the chain always requires immediate execution (aInterval =
|
|
|
|
|
-0), then there will be no end-of-pass delay.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>Note: </b>Task Scheduler uses <b>millis()</b> to
|
|
|
|
|
-determine if tasks are ready to be invoked. Therefore, if you put your device
|
|
|
|
|
-to any “deep” sleep mode disabling timer interrupts, the <b>millis()</b> count
|
|
|
|
|
-will be suspended, leading to effective suspension of scheduling. Upon wake up,
|
|
|
|
|
-active tasks need to be re-enabled, which will effectively reset their internal
|
|
|
|
|
-time scheduling variables to the new value of <b>millis(). </b>Time spent in
|
|
|
|
|
-deep sleep mode should be considered “frozen”, i.e., if a task was scheduled to
|
|
|
|
|
-run in 1 second from now, and device was put to sleep for 5 minutes, upon wake
|
|
|
|
|
-up, the task will still be scheduled 1 second from the time of wake up.
|
|
|
|
|
-Executing <b>enable() </b>function on this tasks will make it run as soon as
|
|
|
|
|
-possible. This is a concern only for tasks which are required to run in a truly
|
|
|
|
|
-periodical manner (in absolute time terms). </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>COMPILE PARAMETERS:</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>This library could be compiled with several options. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>These parameters must be defined before inclusion of the
|
|
|
|
|
-library header file into the sketch.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>#define <b>_TASK_TIMECRITICAL</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>...will compile the library with time critical tracking
|
|
|
|
|
-option enabled.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Time critical option keeps track where next execution time
|
|
|
|
|
-of the task falls, and makes it available via API through Task::<b> getOverrun()
|
|
|
|
|
-</b>function. If <b>getOverrun </b>returns a negative value, this Task’s next
|
|
|
|
|
-execution time is in the past, and task is behind schedule. This most probably
|
|
|
|
|
-means that either task’s callback function runtime is too long, or the
|
|
|
|
|
-execution interval is too short (then schedule is too aggressive).</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>A positive value indicates that task is on schedule, and
|
|
|
|
|
-callback functions have enough time to finish before the next scheduled pass. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>#define <b>_TASK_SLEEP_ON_IDLE_RUN</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>...will compile the library with the <b>sleep</b> option
|
|
|
|
|
-enabled (AVR boards only).</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>When enabled, scheduler will put the microcontroller into <b>SLEEP_MODE_IDLE</b>
|
|
|
|
|
-state if none of the tasks’ callback functions were activated during pass. <b>IDLE</b>
|
|
|
|
|
-state is interrupted by timers once every 1 ms. Helps conserve power. Device
|
|
|
|
|
-in SLEEP_MODE_IDLE wakes up to all hardware and timer interrupts, so scheduling
|
|
|
|
|
-is kept current.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>NOTE: above parameters are DISABLED by default, and need
|
|
|
|
|
-to be explicitly enabled.</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>API DOCUMENTATION:</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>TASKS:</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>CREATION:</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>Task();</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Default constructor. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Takes no parameters and creates
|
|
|
|
|
-a task that could be scheduled to run at every scheduling pass indefinitely,
|
|
|
|
|
-but does not have a callback function defined, so no execution will actually
|
|
|
|
|
-take place. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>All tasks are created <b>disabled</b>
|
|
|
|
|
-by default.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='page-break-after:avoid'><b>Task(unsigned long aInterval,
|
|
|
|
|
-long aIterations, void (*aCallback)(), Scheduler* aScheduler, bool aEnable);</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Constructor with parameters. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Creates a task that is scheduled
|
|
|
|
|
-to run every <aInterval> milliseconds, <aIterations> times,
|
|
|
|
|
-executing <aCallback> function on every pass. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>1.<span
|
|
|
|
|
-style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
|
|
|
|
|
-</span>aInterval is in milliseconds</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>2.<span
|
|
|
|
|
-style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
|
|
|
|
|
-</span>aIteration in number of times, -1 for indefinite execution<br>
|
|
|
|
|
-<b>Note: </b>Tasks do not remember the number of iteration set initially. After
|
|
|
|
|
-the iterations are done, internal iteration counter is 0. If you need to
|
|
|
|
|
-perform another set of iterations, you need to set the number of iterations
|
|
|
|
|
-again. <br>
|
|
|
|
|
-<b>Note: </b>Tasks which performed all their iterations remain active. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>3.<span
|
|
|
|
|
-style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
|
|
|
|
|
-</span>aCallback is a pointer to a void function without parameters</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>4.<span
|
|
|
|
|
-style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
|
|
|
|
|
-</span>aScheduler – <b>optional</b> reference to existing scheduler. If
|
|
|
|
|
-supplied (not NULL) this task will be appended to the task chain of the current
|
|
|
|
|
-scheduler). <b>Default=NULL</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>5.<span
|
|
|
|
|
-style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
|
|
|
|
|
-</span>aEnable – <b>optional</b>. Value of <b>true </b>will create task
|
|
|
|
|
-enabled. <b>Default = false</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>All tasks are created <b>disabled</b>
|
|
|
|
|
-by default (unless aEnable = true). You have to explicitly enable the task for
|
|
|
|
|
-execution.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Enabled task is scheduled for execution
|
|
|
|
|
-immediately. Enable tasks with delay (standard execution interval or specific
|
|
|
|
|
-execution interval) in order to defer first run of the task.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>INFORMATION</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>The following 3 “getter”
|
|
|
|
|
-functions return task status (enabled/disabled), execution interval in
|
|
|
|
|
-milliseconds, number of <b><i>remaining</i></b> iterations. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>bool isEnabled() </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>unsigned long getInterval()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>long getIterations() </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b> </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>long getOverrun()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>If library is compiled with <span
|
|
|
|
|
-style='font-family:"Courier New"'>_TASK_TIMECRITICAL</span> enabled, tasks are
|
|
|
|
|
-monitored for “long running” scenario. A “long running” task is a task that
|
|
|
|
|
-does not finish processing its callback functions quickly, and thus creates a
|
|
|
|
|
-situation for itself and other tasks where they don't run on a scheduled
|
|
|
|
|
-interval, but rather “catch up” and are behind. When task scheduler sets
|
|
|
|
|
-the next execution target time, it adds Task's execution interval to the
|
|
|
|
|
-previously scheduled execution time:</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>
|
|
|
|
|
-<b>next execution time = previous execution time + task execution interval</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>If <b>next execution time</b> happens
|
|
|
|
|
-to be already in the past (<b>next execution time</b> < <b>millis()</b>), then
|
|
|
|
|
-task is considered <b><i>overrun</i></b>. <b>GetOverrun</b> function returns
|
|
|
|
|
-number of milliseconds between next execution time and current time. If the <b>value
|
|
|
|
|
-is negative</b>, the task is overrun by that many milliseconds. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Positive value indicate number
|
|
|
|
|
-of milliseconds of slack this task has for execution purposes. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>bool isFirstIteration()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>bool isLastIteration()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>For tasks with a defined number
|
|
|
|
|
-of iterations, indicates whether current pass is a first or a last iteration of
|
|
|
|
|
-the task (respectively). </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='page-break-after:avoid'><b>CONTROL:</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void enable();</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Enables the task, and schedules
|
|
|
|
|
-it for immediate execution (without delay) at this or next scheduling pass
|
|
|
|
|
-depending on when the task was enabled. Scheduler will execute the next pass
|
|
|
|
|
-without any delay because there is a task which was enabled and requires
|
|
|
|
|
-execution. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void delay();</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Schedules the task for execution
|
|
|
|
|
-after a delay (aInterval), but does not change the enabled/disabled status of
|
|
|
|
|
-the task. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b> </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void enableDelayed();</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Enables the task, and schedules
|
|
|
|
|
-it for execution after a delay (aInterval). </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void enableDelayed (unsigned long aDelay);</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Enables the task, and schedules
|
|
|
|
|
-it for execution after a specific delay (aDelay, which maybe different from aInterval).
|
|
|
|
|
-</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void restart();</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>For tasks with limited number of
|
|
|
|
|
-iterations only, <b>restart</b> function will re-enable the task, set the
|
|
|
|
|
-number of iterations back to when the task was created and and schedule the
|
|
|
|
|
-task for execution as soon as possible.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void restartDelayed (unsigned long aDelay);</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Same as <b>restart() </b>function,
|
|
|
|
|
-with the only difference being that Task is scheduled to run first iteration
|
|
|
|
|
-after a delay = <b>aDelay</b> milliseconds.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b> </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void disable();</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Disables the task. Scheduler
|
|
|
|
|
-will not execute this task any longer, even if it remains in the chain. Task
|
|
|
|
|
-can be later re-enabled for execution. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void disableOnLastIteration (bool aBool);</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Controls iterative task behavior
|
|
|
|
|
-on the last iteration. If <b>aBool</b> is <b>true</b> task will be disabled
|
|
|
|
|
-after last iteration. If <b>aBool</b> is <b>false</b>, task will remain active
|
|
|
|
|
-(but not invoked until new number of iterations is set)</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void set(unsigned long aInterval, long aIterations, void (*aCallback)());</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Allows dynamic control of all
|
|
|
|
|
-task execution parameters in one function call. If task being modified is
|
|
|
|
|
-active, it will be scheduled for execution immediately. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Next three “setter” functions allow changes of individual
|
|
|
|
|
-task execution control parameters. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>void setInterval (unsigned
|
|
|
|
|
-long aInterval) </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>void setIterations (long aIterations)
|
|
|
|
|
-</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>void setCallback (void
|
|
|
|
|
-(*aCallback)()) </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>Note: </b>Next execution time calculation takes place <b>after</b>
|
|
|
|
|
-the callback function is called, so new interval will be used immediately by
|
|
|
|
|
-the scheduler. For the situations when one task is changing the interval
|
|
|
|
|
-parameter for the other, <b>setInterval</b> function calls <b>delay </b>explicitly
|
|
|
|
|
-to guarantee schedule change, however it <b>does not </b>enable the task if
|
|
|
|
|
-task is disabled. If task being modified is active, <b>setIterations </b>will
|
|
|
|
|
-make the task be scheduled for execution immediately.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b> </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>TASK SCHEDULER:</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>CREATION:</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-bottom:12.0pt'><b>Scheduler()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Default constructor. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Takes no parameters. Creates
|
|
|
|
|
-task scheduler with default parameters and an empty task queue. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void init()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Initializes the task queue and
|
|
|
|
|
-scheduler parameters, Executed as part of constructor, so don't need to be
|
|
|
|
|
-explicitly called after creation.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>Note: </b>be default (if
|
|
|
|
|
-compiled with <span style='font-family:"Courier New"'>_TASK_TIMECRITICAL</span>
|
|
|
|
|
-enabled) scheduler is allowed to put processor to IDLE sleep mode. If this
|
|
|
|
|
-behavior was changed via <b>allowSleep() </b>function, <b>inti() </b>will <b>NOT</b>
|
|
|
|
|
-reset allow sleep particular parameter. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><br>
|
|
|
|
|
-<b>void addTask(Task& aTask)</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Adds task aTask to the execution
|
|
|
|
|
-queue (or chain) of tasks by appending it to the end of the chain. If two tasks
|
|
|
|
|
-are scheduled for execution, the sequence will match the order tasks are
|
|
|
|
|
-appended to the chain. However, in reality, due to different timing of task
|
|
|
|
|
-execution, the actual order will be different. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>Note: </b>Currently, changing
|
|
|
|
|
-the execution dynamically is not supported. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>If you need to reorder the queue
|
|
|
|
|
-– initialize the scheduler and re-add the tasks in a different order. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><br>
|
|
|
|
|
-<b>void deleteTask(Task& aTask)</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Deletes task aTask from the
|
|
|
|
|
-execution chain. The chain of remaining tasks is linked together (i.e</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>if original task chain is 1 →
|
|
|
|
|
-2 → 3 → 4, deleting 3 will result in 1 → 2 → 4).</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><b>Note: </b>it is not required
|
|
|
|
|
-to delete a task from the chain. A disabled task will not be executed anyway,
|
|
|
|
|
-but you save a few microseconds per scheduling pass by deleting it, since it is
|
|
|
|
|
-not even considered for execution. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>An example of proper use of this
|
|
|
|
|
-function would be running some sort of <b>initialize</b> task in the chain, and
|
|
|
|
|
-then deleting it from the chain since it only needs to run once. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void allowSleep(bool aState) </b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Available in API only if compiled
|
|
|
|
|
-with <span style='font-family:"Courier New"'>_TASK_TIMECRITICAL</span> enabled.
|
|
|
|
|
-Controls whether scheduler is allowed (<b>aState =true</b>), or not (<b>aState =false</b>)
|
|
|
|
|
-to put processor into IDLE sleep mode in case not tasks are scheduled to run.</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>The <b>default</b> behavior of
|
|
|
|
|
-scheduler upon creation is to allow sleep mode. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><br>
|
|
|
|
|
-<b>void enableAll()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b>void disableAll()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>enables and disables
|
|
|
|
|
-(respectively) all tasks in the chain. Convenient if your need to
|
|
|
|
|
-enable/disable majority of the tasks (i.e. disable all and then enable one). </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-bottom:12.0pt'><br>
|
|
|
|
|
-<b>Task& currentTask()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Returns reference to the task,
|
|
|
|
|
-currently executing via <b>execute()</b> loop. Could be used by callback
|
|
|
|
|
-functions to identify which of the </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><br>
|
|
|
|
|
-<b>void execute()</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'>Executes one scheduling pass,
|
|
|
|
|
-including end-of-pass sleep. This function typically placed inside the <b>loop()</b>
|
|
|
|
|
-function of the sketch. Since <b>execute</b> exits after every pass, you can
|
|
|
|
|
-put additional statements after <b>execute</b> inside the <b>loop()</b> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='page-break-after:avoid'><b>IMPLEMENTATION SCENARIOS
|
|
|
|
|
-AND IDEAS:</b></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<ol style='margin-top:0in' start=1 type=1>
|
|
|
|
|
- <li class=MsoNormal><b>EVENT DRIVEN PROGRAMMING</b></li>
|
|
|
|
|
-</ol>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Each of the processes of your application becomes a separate
|
|
|
|
|
-and distinct programming area, which may or may not interact and control each
|
|
|
|
|
-other. </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Example: </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>In a plant watering system you need to measure soil
|
|
|
|
|
-humidity, control pump and display the results</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Each of the areas becomes a task:</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>Task
|
|
|
|
|
-<b>tMeasure</b> (TMEASURE_INTERVAL*SECOND, -1, &measureCallback);<br>
|
|
|
|
|
-Task <b>tWater</b> (TWATER_INTERVAL*SECOND, RETRIES,
|
|
|
|
|
-&waterCallback);<br>
|
|
|
|
|
-Task <b>tDisplay</b> (TDISPLAY_INTERVAL*SECOND, -1, &displayCallback); </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>Scheduler
|
|
|
|
|
-<b>taskManager</b>;</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Further, once you turn on the pump, you keep it running for
|
|
|
|
|
-TWATER_INTERVAL interval and then turn it off. Turning off a pump is also a
|
|
|
|
|
-task which only needs to run once for every time the pump is turned on:</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>Task
|
|
|
|
|
-<b>tWaterOff</b> (WATERTIME*SECOND, 1,</span><span style='font-family:"Courier New"'>
|
|
|
|
|
-&waterOffCallback);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal>Example of the callback function:</p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>void waterOffCallback() {<br>
|
|
|
|
|
- motorOff();<br>
|
|
|
|
|
- tWater.enableDelayed();<br>
|
|
|
|
|
-}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>or</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>void waterCallback() {<br>
|
|
|
|
|
- if (tWater.getIterations()) {</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>// If this is not the last iteration = turn the pump
|
|
|
|
|
-on<br>
|
|
|
|
|
- motorOn();<br>
|
|
|
|
|
- tWaterOff.set(parameters.watertime * SECOND, 1,
|
|
|
|
|
-&waterOffCallback);<br>
|
|
|
|
|
- tWaterOff.enableDelayed();<br>
|
|
|
|
|
- return;<br>
|
|
|
|
|
- }</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>// We could not reach target humidity – something is
|
|
|
|
|
-wrong<br>
|
|
|
|
|
- motorOff;<br>
|
|
|
|
|
- taskManager.disableAll();<br>
|
|
|
|
|
- tError.enable();<br>
|
|
|
|
|
-}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Your
|
|
|
|
|
-sample <b>setup</b>() and <b>loop</b>() (partially) are as follows. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>Note:
|
|
|
|
|
-</span></b><span style='font-family:"Times New Roman","serif"'>please note that
|
|
|
|
|
-tWater is <b>not</b> activated during setup(). It is activated by tMeasure
|
|
|
|
|
-callback once the watering conditions are met. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>
|
|
|
|
|
-</span><span style='font-family:"Courier New"'>setup()</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Courier New"'>
|
|
|
|
|
- ...</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-tWater.setIterations(parameters.retries);<br>
|
|
|
|
|
- tWaterOff.setInterval(parameters.watertime * SECOND);<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-<br>
|
|
|
|
|
- taskManager.init();<br>
|
|
|
|
|
- taskManager.addTask(tMeasure);<br>
|
|
|
|
|
- taskManager.addTask(tDisplay);<br>
|
|
|
|
|
- taskManager.addTask(tWater);<br>
|
|
|
|
|
- taskManager.addTask(tWaterOff);<br>
|
|
|
|
|
- <br>
|
|
|
|
|
- tMeasure.enable();<br>
|
|
|
|
|
- tDisplay.enable();<br>
|
|
|
|
|
-<br>
|
|
|
|
|
- currentHumidity = measureHumidity();<br>
|
|
|
|
|
-}<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-void loop ()<br>
|
|
|
|
|
-{<br>
|
|
|
|
|
- taskManager.execute();<br>
|
|
|
|
|
-}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'> </p>
|
|
|
|
|
-
|
|
|
|
|
-<ol style='margin-top:0in' start=2 type=1>
|
|
|
|
|
- <li class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>“NATIVE”
|
|
|
|
|
- SUPPORT FOR FINITE STATE MACHINE</span></b></li>
|
|
|
|
|
-</ol>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Define
|
|
|
|
|
-“states” as callback function or functions. Each callback function executes
|
|
|
|
|
-activities specific to a “state” and then “transitions” to the next state by
|
|
|
|
|
-assigning next callback function to the task. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Transition
|
|
|
|
|
-from one state to the next is achieved by setting next callback function at the
|
|
|
|
|
-end of preceding one. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>Note:
|
|
|
|
|
-</span></b><span style='font-family:"Times New Roman","serif"'>do not call the
|
|
|
|
|
-next callback function. Let the schedule take care of that during the next
|
|
|
|
|
-pass. (Thus letting other tasks run). </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Example:
|
|
|
|
|
-Blinking LED 2 times a second could be achieved this way</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>Task
|
|
|
|
|
-tLedBlinker (500, -1, &ledOnCallback);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>Scheduler
|
|
|
|
|
-taskManager;</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>void
|
|
|
|
|
-ledOnCallback() {</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-turnLedOn();</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-tLedBlinker.setCallback(&ledOffCallback);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>void
|
|
|
|
|
-ledOffCallback() {</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-turnLedOff();</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-tLedBlinker.setCallback(&ledOnCallback);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>setup()
|
|
|
|
|
-{</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-taskManager.init();<br>
|
|
|
|
|
- taskManager.addTask(tLedBlinker);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-tLedBlinker.enable();</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>loop
|
|
|
|
|
-() {</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
|
|
|
|
|
-taskManager.execute();</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-family:"Courier New"'>}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Obviously
|
|
|
|
|
-the example is simple, but gives the idea of how the tasks could be used to go
|
|
|
|
|
-through states.</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<ol style='margin-top:0in' start=3 type=1>
|
|
|
|
|
- <li class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>MULTIPLE
|
|
|
|
|
- POSSIBLE CALLBACKS FOR TASK</span></b></li>
|
|
|
|
|
-</ol>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>There may
|
|
|
|
|
-be a need to select an option for callback function based on certain criteria,
|
|
|
|
|
-or randomly. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>You can
|
|
|
|
|
-achieve that by defining an array of callback function pointers and selecting
|
|
|
|
|
-one based on the criteria you need. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Example:
|
|
|
|
|
-when a robot detects an obstacle, it may go left, right backwards, etc. Each of
|
|
|
|
|
-the “directions” or “behaviors” are represented by a different callback
|
|
|
|
|
-function. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Another
|
|
|
|
|
-example of using multiple callbacks:</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>You may
|
|
|
|
|
-need to “initialize” variables for a particular task.</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>In this
|
|
|
|
|
-case, define a tasks with two callbacks:</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>Task <b>tWork</b> (T_INTERVAL, -1,
|
|
|
|
|
-&workCallbackInit);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>…</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>void workCallbackInit() {</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> // do your
|
|
|
|
|
-initializationstuff here</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> // finally assigne
|
|
|
|
|
-the main callback function </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>
|
|
|
|
|
-tWork.setCallback(&workCallback);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>void workCallback() {</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> // main callback
|
|
|
|
|
-function</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> …</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>The task
|
|
|
|
|
-will initialize during first execution pass and switch to “regular” callback
|
|
|
|
|
-execution starting with second pass. There is a delay between first and second
|
|
|
|
|
-passes of the task (scheduling period, if defined). In order to execute the
|
|
|
|
|
-second pass immediately after initialization first pass, change the above code
|
|
|
|
|
-like this:</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>void workCallbackInit() {</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> // do your
|
|
|
|
|
-initializationstuff here</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> // finally assigne the
|
|
|
|
|
-main callback function </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>
|
|
|
|
|
-tWork.setCallback(&workCallback);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'> tWork.enable();</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>The task
|
|
|
|
|
-will run initialization first, then immediately second pass, and then switch to
|
|
|
|
|
-processing at regular intervals starting with a third pass. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal> </p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<ol style='margin-top:0in' start=4 type=1>
|
|
|
|
|
- <li class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>INTERRUP-DRIVEN
|
|
|
|
|
- EXECUTION SUPPORT </span></b></li>
|
|
|
|
|
-</ol>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>In case
|
|
|
|
|
-of interrupt-driven program flow, tasks could be scheduled to run once to
|
|
|
|
|
-request asynchronous execution (request), and then re-enabled (restarted) again
|
|
|
|
|
-with a different callback function to process the results. </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>Example</span></b><span
|
|
|
|
|
-style='font-family:"Times New Roman","serif"'>: event driven distance
|
|
|
|
|
-calculation for ultrasonic pulses. EchoPin #6 triggers pin change interrupts on
|
|
|
|
|
-rising and falling edges to determine the length of ultrasonic pulse.</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>#include <DirectIO.h><br>
|
|
|
|
|
-#include <TaskScheduler.h><br>
|
|
|
|
|
-#include <PinChangeInt.h><br>
|
|
|
|
|
-<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-#define TRIGGERPIN 5<br>
|
|
|
|
|
-#define ECHOPIN 6<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-Output<TRIGGERPIN> pTrigger;<br>
|
|
|
|
|
-Input<ECHOPIN> pEcho;<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-Scheduler r;<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-Task tMeasure(1000, -1, &measureCallback);<br>
|
|
|
|
|
-Task tDisplay(1000, -1, &displayCallback);<br>
|
|
|
|
|
-Task tPing(0, 1, &pingCalcCallback);<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-volatile bool pulseBusy = false;<br>
|
|
|
|
|
-volatile bool pulseTimeout = false;<br>
|
|
|
|
|
-volatile unsigned long pulseStart = 0;<br>
|
|
|
|
|
-volatile unsigned long pulseStop = 0;<br>
|
|
|
|
|
-volatile unsigned long pingDistance = 0;<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-void pingTrigger(unsigned long aTimeout) {<br>
|
|
|
|
|
- if (pulseBusy) return; // do not trigger if in the middle of a
|
|
|
|
|
-pulse<br>
|
|
|
|
|
- if (pEcho == HIGH) return; // do not trigger if ECHO pin is high<br>
|
|
|
|
|
- <br>
|
|
|
|
|
- pulseBusy = true;<br>
|
|
|
|
|
- pulseTimeout = false;</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'><br>
|
|
|
|
|
- pTrigger = LOW;<br>
|
|
|
|
|
- delayMicroseconds(4);<br>
|
|
|
|
|
- pTrigger = HIGH;<br>
|
|
|
|
|
-<br>
|
|
|
|
|
- tPing.setInterval (aTimeout);<br>
|
|
|
|
|
-<br>
|
|
|
|
|
- delayMicroseconds(10);<br>
|
|
|
|
|
- pTrigger = LOW; </span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>
|
|
|
|
|
-tPing.restartDelayed(); // timeout countdown starts now</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>// will start the pulse clock on the rising edge of
|
|
|
|
|
-ECHO pin</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>
|
|
|
|
|
-PCintPort::attachInterrupt(ECHOPIN, &pingStartClock, RISING); <br>
|
|
|
|
|
-}<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
|
|
|
|
|
-font-family:"Courier New"'>// Start clock on the <b>rising</b> edge of the
|
|
|
|
|
-ultrasonic pulse<br>
|
|
|
|
|
-void pingStartClock() {<br>
|
|
|
|
|
- pulseStart = micros();<br>
|
|
|
|
|
- PCintPort::detachInterrupt(ECHOPIN); // not sure this is necessary<br>
|
|
|
|
|
- PCintPort::attachInterrupt(ECHOPIN, &pingStopClock, FALLING); <br>
|
|
|
|
|
- tPing.restartDelayed();<br>
|
|
|
|
|
-}<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-// Stop clock on the <b>falling</b> edge of the ultrasonic pulse<br>
|
|
|
|
|
-void pingStopClock() {<br>
|
|
|
|
|
- pulseStop = micros();<br>
|
|
|
|
|
- PcintPort::detachInterrupt(ECHOPIN);</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>
|
|
|
|
|
-pingDistance = pulseStop - pulseStart;<br>
|
|
|
|
|
- pulseBusy = false;<br>
|
|
|
|
|
- tPing.disable(); // disable timeout<br>
|
|
|
|
|
-}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>//
|
|
|
|
|
-Stop clock because of the timeout – the wave did not return<br>
|
|
|
|
|
-void pingCalcCallback() {<br>
|
|
|
|
|
- if (pulseBusy) {<br>
|
|
|
|
|
- pingStopClock();<br>
|
|
|
|
|
- }<br>
|
|
|
|
|
- pulseTimeout = true;<br>
|
|
|
|
|
-}<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-// Initial measure callback sets the trigger<br>
|
|
|
|
|
-void measureCallback() {<br>
|
|
|
|
|
- if (pulseBusy) { // already measuring, try again<br>
|
|
|
|
|
- tMeasure.enable();<br>
|
|
|
|
|
- return;<br>
|
|
|
|
|
- }<br>
|
|
|
|
|
- pingTrigger(30); // 30 milliseconds or max range of ~5.1 meters<br>
|
|
|
|
|
- tMeasure.setCallback(&measureCallbackWait);<br>
|
|
|
|
|
-}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-<p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
|
|
|
|
|
-margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>//
|
|
|
|
|
-Wait for the measurement to <br>
|
|
|
|
|
-void measureCallbackWait() {<br>
|
|
|
|
|
- if (pulseBusy) return;<br>
|
|
|
|
|
- tMeasure.setCallback(&measureCallback); <br>
|
|
|
|
|
-}<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-bool state = true;<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-void displayCallback() {<br>
|
|
|
|
|
- char d[256];<br>
|
|
|
|
|
- <br>
|
|
|
|
|
- unsigned long cm = pingDistance * 17 / 100; // cm<br>
|
|
|
|
|
- <br>
|
|
|
|
|
- snprintf(d, 256, "pulseStart = %8lu\tpulseStop=%8lu\tdistance,
|
|
|
|
|
-cm=%8lu", pulseStart, pulseStop, cm);<br>
|
|
|
|
|
- Serial.println(d);<br>
|
|
|
|
|
- <br>
|
|
|
|
|
-}<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-void setup() {<br>
|
|
|
|
|
- // put your setup code here, to run once:<br>
|
|
|
|
|
- <br>
|
|
|
|
|
- Serial.begin(115200);<br>
|
|
|
|
|
- <br>
|
|
|
|
|
-<br>
|
|
|
|
|
- pTrigger = LOW;<br>
|
|
|
|
|
- pEcho = LOW;<br>
|
|
|
|
|
- <br>
|
|
|
|
|
- r.init();<br>
|
|
|
|
|
- r.addTask(tDisplay);<br>
|
|
|
|
|
- r.addTask(tMeasure);<br>
|
|
|
|
|
- r.addTask(tPing);<br>
|
|
|
|
|
- <br>
|
|
|
|
|
- r.enableAll();<br>
|
|
|
|
|
- tPing.disable();<br>
|
|
|
|
|
-}<br>
|
|
|
|
|
-<br>
|
|
|
|
|
-void loop() {<br>
|
|
|
|
|
- // put your main code here, to run repeatedly:<br>
|
|
|
|
|
- r.execute();<br>
|
|
|
|
|
-}</span></p>
|
|
|
|
|
-
|
|
|
|
|
-</div>
|
|
|
|
|
-
|
|
|
|
|
-</body>
|
|
|
|
|
-
|
|
|
|
|
-</html>
|
|
|
|
|
|
|
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
|
|
+<HTML>
|
|
|
|
|
+<HEAD>
|
|
|
|
|
+ <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
|
|
|
|
|
+ <TITLE></TITLE>
|
|
|
|
|
+ <META NAME="GENERATOR" CONTENT="LibreOffice 3.5 (Linux)">
|
|
|
|
|
+ <META NAME="CREATED" CONTENT="20150206;16300000">
|
|
|
|
|
+ <META NAME="CHANGEDBY" CONTENT="Anatoli Arkhipenko">
|
|
|
|
|
+ <META NAME="CHANGED" CONTENT="20150921;21210000">
|
|
|
|
|
+ <META NAME="Info 1" CONTENT="">
|
|
|
|
|
+ <META NAME="Info 2" CONTENT="">
|
|
|
|
|
+ <META NAME="Info 3" CONTENT="">
|
|
|
|
|
+ <META NAME="Info 4" CONTENT="">
|
|
|
|
|
+ <STYLE TYPE="text/css">
|
|
|
|
|
+ <!--
|
|
|
|
|
+ @page { margin: 0.79in }
|
|
|
|
|
+ P { margin-bottom: 0.08in; direction: ltr; color: #000000; widows: 0; orphans: 0 }
|
|
|
|
|
+ P.western { font-family: "Liberation Serif", "Times New Roman", serif; font-size: 12pt; so-language: en-US }
|
|
|
|
|
+ P.cjk { font-family: "WenQuanYi Micro Hei", "MS Mincho"; font-size: 12pt; so-language: zh-CN }
|
|
|
|
|
+ P.ctl { font-family: "Lohit Hindi", "MS Mincho"; font-size: 12pt; so-language: hi-IN }
|
|
|
|
|
+ -->
|
|
|
|
|
+ </STYLE>
|
|
|
|
|
+</HEAD>
|
|
|
|
|
+<BODY LANG="en-US" TEXT="#000000" DIR="LTR">
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Task Scheduler –
|
|
|
|
|
+cooperative multitasking for Arduino microcontrollers</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Version 1.6:
|
|
|
|
|
+2015-09-22</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>REQUIREMENT</B>:</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">A lightweight
|
|
|
|
|
+implementation of the task scheduling supporting:</P>
|
|
|
|
|
+<OL>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">execution period
|
|
|
|
|
+ (n times per second)</P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">number of
|
|
|
|
|
+ iterations (n times)</P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">execution of tasks
|
|
|
|
|
+ in predefined sequence</P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">dynamic change of
|
|
|
|
|
+ the execution parameters for both tasks and execution schedule</P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">power saving via
|
|
|
|
|
+ entering IDLE sleep mode if no tasks are scheduled to run</P>
|
|
|
|
|
+</OL>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>IDEA</B>:</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">“Task� is a
|
|
|
|
|
+container concept that links together:</P>
|
|
|
|
|
+<OL>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">Execution interval</P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">Number of
|
|
|
|
|
+ execution iterations</P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">A piece of code
|
|
|
|
|
+ performing the task activities (callback function)</P>
|
|
|
|
|
+</OL>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Tasks are linked into
|
|
|
|
|
+execution chains, which are processed by the “Scheduler� in the
|
|
|
|
|
+order they are linked.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Tasks are responsible
|
|
|
|
|
+for supporting cooperative multitasking by being “good neighbors�,
|
|
|
|
|
+i.e., running their callback functions in a non-blocking way and
|
|
|
|
|
+releasing control as soon as possible.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">“Scheduler� is
|
|
|
|
|
+executing Tasks' callback functions in the order the tasks were added
|
|
|
|
|
+to the chain, from first to last. Scheduler stops and exists after
|
|
|
|
|
+processing the chain once in order to allow other statements in the
|
|
|
|
|
+main code of <B>loop()</B> function to run. This a “scheduling
|
|
|
|
|
+pass�.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">If compiled with
|
|
|
|
|
+<FONT FACE="Courier New, monospace">_TASK_SLEEP_ON_IDLE_RUN</FONT>
|
|
|
|
|
+enabled, the scheduler will place processor into IDLE sleep mode (for
|
|
|
|
|
+approximately 1 ms, as the timer interrupt will wake it up), after
|
|
|
|
|
+what is determined to be an “idle� pass. An Idle Pass is a pass
|
|
|
|
|
+through the chain when no Tasks were scheduled to run their callback
|
|
|
|
|
+functions. This is done to avoid repetitive empty passes through the
|
|
|
|
|
+chain when no tasks need to be executed. If any of the tasks in the
|
|
|
|
|
+chain always requires immediate execution (aInterval = 0), then there
|
|
|
|
|
+will be no end-of-pass delay.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Task
|
|
|
|
|
+Scheduler uses <B>millis()</B> to determine if tasks are ready to be
|
|
|
|
|
+invoked. Therefore, if you put your device to any “deep� sleep
|
|
|
|
|
+mode disabling timer interrupts, the <B>millis()</B> count will be
|
|
|
|
|
+suspended, leading to effective suspension of scheduling. Upon wake
|
|
|
|
|
+up, active tasks need to be re-enabled, which will effectively reset
|
|
|
|
|
+their internal time scheduling variables to the new value of
|
|
|
|
|
+<B>millis(). </B>Time spent in deep sleep mode should be considered
|
|
|
|
|
+“frozen�, i.e., if a task was scheduled to run in 1 second from
|
|
|
|
|
+now, and device was put to sleep for 5 minutes, upon wake up, the
|
|
|
|
|
+task will still be scheduled 1 second from the time of wake up.
|
|
|
|
|
+Executing <B>enable() </B>function on this tasks will make it run as
|
|
|
|
|
+soon as possible. This is a concern only for tasks which are required
|
|
|
|
|
+to run in a truly periodical manner (in absolute time terms).
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>COMPILE PARAMETERS:</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">This library could be
|
|
|
|
|
+compiled with several options.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">These parameters must
|
|
|
|
|
+be defined before inclusion of the library header file into the
|
|
|
|
|
+sketch.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">#define
|
|
|
|
|
+<B>_TASK_TIMECRITICAL</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">...will compile the
|
|
|
|
|
+library with time critical tracking option enabled.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Time critical option
|
|
|
|
|
+keeps track where next execution time of the task falls, and makes it
|
|
|
|
|
+available via API through Task::<B> getOverrun() </B>function. If
|
|
|
|
|
+<B>getOverrun </B>returns a negative value, this Task’s next
|
|
|
|
|
+execution time is in the past, and task is behind schedule. This most
|
|
|
|
|
+probably means that either task’s callback function runtime is too
|
|
|
|
|
+long, or the execution interval is too short (then schedule is too
|
|
|
|
|
+aggressive).</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">A positive value
|
|
|
|
|
+indicates that task is on schedule, and callback functions have
|
|
|
|
|
+enough time to finish before the next scheduled pass.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">#define
|
|
|
|
|
+<B>_TASK_SLEEP_ON_IDLE_RUN</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">...will compile the
|
|
|
|
|
+library with the <B>sleep</B> option enabled (AVR boards only).</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">When enabled, scheduler
|
|
|
|
|
+will put the microcontroller into <B>SLEEP_MODE_IDLE</B> state if
|
|
|
|
|
+none of the tasks’ callback functions were activated during pass.
|
|
|
|
|
+<B>IDLE</B> state is interrupted by timers once every 1 ms. Helps
|
|
|
|
|
+conserve power. Device in SLEEP_MODE_IDLE wakes up to all hardware
|
|
|
|
|
+and timer interrupts, so scheduling is kept current.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>NOTE: above
|
|
|
|
|
+parameters are DISABLED by default, and need to be explicitly
|
|
|
|
|
+enabled.</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>API DOCUMENTATION:</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>TASKS:</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">CREATION:</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Task();</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Default
|
|
|
|
|
+constructor.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes
|
|
|
|
|
+no parameters and creates a task that could be scheduled to run at
|
|
|
|
|
+every scheduling pass indefinitely, but does not have a callback
|
|
|
|
|
+function defined, so no execution will actually take place.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">All
|
|
|
|
|
+tasks are created <B>disabled</B> by default.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
|
|
|
|
|
+<B>Task(unsigned long aInterval, long aIterations, void
|
|
|
|
|
+(*aCallback)(), Scheduler* aScheduler, bool aEnable);</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Constructor
|
|
|
|
|
+with parameters.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Creates
|
|
|
|
|
+a task that is scheduled to run every <aInterval> milliseconds,
|
|
|
|
|
+<aIterations> times, executing <aCallback> function on
|
|
|
|
|
+every pass.
|
|
|
|
|
+</P>
|
|
|
|
|
+<OL>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">aInterval is in
|
|
|
|
|
+ milliseconds</P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">aIteration in
|
|
|
|
|
+ number of times, -1 for indefinite execution<BR><B>Note: </B>Tasks
|
|
|
|
|
+ do not remember the number of iteration set initially. After the
|
|
|
|
|
+ iterations are done, internal iteration counter is 0. If you need to
|
|
|
|
|
+ perform another set of iterations, you need to set the number of
|
|
|
|
|
+ iterations again. <BR><B>Note: </B>Tasks which performed all their
|
|
|
|
|
+ iterations remain active.
|
|
|
|
|
+ </P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">aCallback is a
|
|
|
|
|
+ pointer to a void function without parameters</P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">aScheduler –
|
|
|
|
|
+ <B>optional</B> reference to existing scheduler. If supplied (not
|
|
|
|
|
+ NULL) this task will be appended to the task chain of the current
|
|
|
|
|
+ scheduler). <B>Default=NULL</B></P>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">aEnable –
|
|
|
|
|
+ <B>optional</B>. Value of <B>true </B>will create task enabled.
|
|
|
|
|
+ <B>Default = false</B></P>
|
|
|
|
|
+</OL>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">All
|
|
|
|
|
+tasks are created <B>disabled</B> by default (unless aEnable = true).
|
|
|
|
|
+You have to explicitly enable the task for execution.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enabled
|
|
|
|
|
+task is scheduled for execution immediately. Enable tasks with delay
|
|
|
|
|
+(standard execution interval or specific execution interval) in order
|
|
|
|
|
+to defer first run of the task.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>INFORMATION</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">The
|
|
|
|
|
+following 3 “getter� functions return task status
|
|
|
|
|
+(enabled/disabled), execution interval in milliseconds, number of
|
|
|
|
|
+<I><B>remaining</B></I> iterations.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>bool
|
|
|
|
|
+isEnabled() </B>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>unsigned
|
|
|
|
|
+long getInterval()</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>long
|
|
|
|
|
+getIterations() </B>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>long getOverrun()</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
|
|
|
|
|
+library is compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
|
|
|
|
|
+enabled, tasks are monitored for “long running� scenario. A “long
|
|
|
|
|
+running� task is a task that does not finish processing its
|
|
|
|
|
+callback functions quickly, and thus creates a situation for itself
|
|
|
|
|
+and other tasks where they don't run on a scheduled interval, but
|
|
|
|
|
+rather “catch up� and are behind. When task scheduler sets the
|
|
|
|
|
+next execution target time, it adds Task's execution interval to the
|
|
|
|
|
+previously scheduled execution time:</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> <B>next
|
|
|
|
|
+execution time = previous execution time + task execution interval</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
|
|
|
|
|
+<B>next execution time</B> happens to be already in the past (<B>next
|
|
|
|
|
+execution time</B> < <B>millis()</B>), then task is considered
|
|
|
|
|
+<I><B>overrun</B></I>. <B>GetOverrun</B> function returns number of
|
|
|
|
|
+milliseconds between next execution time and current time. If the
|
|
|
|
|
+<B>value is negative</B>, the task is overrun by that many
|
|
|
|
|
+milliseconds.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Positive
|
|
|
|
|
+value indicate number of milliseconds of slack this task has for
|
|
|
|
|
+execution purposes.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool
|
|
|
|
|
+isFirstIteration()</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool
|
|
|
|
|
+isLastIteration()</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">For
|
|
|
|
|
+tasks with a defined number of iterations, indicates whether current
|
|
|
|
|
+pass is a first or a last iteration of the task (respectively).
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
|
|
|
|
|
+<B>CONTROL:</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void enable();</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables
|
|
|
|
|
+the task, and schedules it for immediate execution (without delay) at
|
|
|
|
|
+this or next scheduling pass depending on when the task was enabled.
|
|
|
|
|
+Scheduler will execute the next pass without any delay because there
|
|
|
|
|
+is a task which was enabled and requires execution.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void delay();</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Schedules
|
|
|
|
|
+the task for execution after a delay (aInterval), but does not change
|
|
|
|
|
+the enabled/disabled status of the task.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void
|
|
|
|
|
+enableDelayed();</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables
|
|
|
|
|
+the task, and schedules it for execution after a delay (aInterval).
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void enableDelayed
|
|
|
|
|
+(unsigned long aDelay);</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables
|
|
|
|
|
+the task, and schedules it for execution after a specific delay
|
|
|
|
|
+(aDelay, which maybe different from aInterval).
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void restart();</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">For
|
|
|
|
|
+tasks with limited number of iterations only, <B>restart</B> function
|
|
|
|
|
+will re-enable the task, set the number of iterations back to when
|
|
|
|
|
+the task was created and and schedule the task for execution as soon
|
|
|
|
|
+as possible.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void restartDelayed
|
|
|
|
|
+(unsigned long aDelay);</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Same
|
|
|
|
|
+as <B>restart() </B>function, with the only difference being that
|
|
|
|
|
+Task is scheduled to run first iteration after a delay = <B>aDelay</B>
|
|
|
|
|
+milliseconds.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void disable();</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Disables
|
|
|
|
|
+the task. Scheduler will not execute this task any longer, even if it
|
|
|
|
|
+remains in the chain. Task can be later re-enabled for execution.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void set(unsigned
|
|
|
|
|
+long aInterval, long aIterations, void (*aCallback)());</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Allows
|
|
|
|
|
+dynamic control of all task execution parameters in one function
|
|
|
|
|
+call.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Next three “setter�
|
|
|
|
|
+functions allow changes of individual task execution control
|
|
|
|
|
+parameters.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void
|
|
|
|
|
+setInterval (unsigned long aInterval) </B>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void
|
|
|
|
|
+setIterations (long aIterations) </B>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void
|
|
|
|
|
+setCallback (void (*aCallback)()) </B>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Next
|
|
|
|
|
+execution time calculation takes place <B>after</B> the callback
|
|
|
|
|
+function is called, so new interval will be used immediately by the
|
|
|
|
|
+scheduler. For the situations when one task is changing the interval
|
|
|
|
|
+parameter for the other, <B>setInterval</B> function calls <B>delay
|
|
|
|
|
+</B>explicitly to guarantee schedule change, however it <B>does not
|
|
|
|
|
+</B>enable the task if task is disabled.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B><SPAN STYLE="font-weight: normal">Tasks
|
|
|
|
|
+that ran through all their allocated iterations are disabled.
|
|
|
|
|
+</SPAN><B>SetIterations()</B><SPAN STYLE="font-weight: normal">
|
|
|
|
|
+method </SPAN><B>DOES NOT</B><SPAN STYLE="font-weight: normal">
|
|
|
|
|
+enable the task. Either enable explicitly, or use restart methods. </SPAN>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>TASK SCHEDULER:</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>CREATION:</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Scheduler()</B><BR><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Default
|
|
|
|
|
+constructor.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes
|
|
|
|
|
+no parameters. Creates task scheduler with default parameters and an
|
|
|
|
|
+empty task queue.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void init()</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Initializes
|
|
|
|
|
+the task queue and scheduler parameters, Executed as part of
|
|
|
|
|
+constructor, so don't need to be explicitly called after creation.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
|
|
|
|
|
+</B>be default (if compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
|
|
|
|
|
+enabled) scheduler is allowed to put processor to IDLE sleep mode. If
|
|
|
|
|
+this behavior was changed via <B>allowSleep() </B>function, <B>inti()
|
|
|
|
|
+</B>will <B>NOT</B> reset allow sleep particular parameter.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void
|
|
|
|
|
+addTask(Task& aTask)</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Adds
|
|
|
|
|
+task aTask to the execution queue (or chain) of tasks by appending it
|
|
|
|
|
+to the end of the chain. If two tasks are scheduled for execution,
|
|
|
|
|
+the sequence will match the order tasks are appended to the chain.
|
|
|
|
|
+However, in reality, due to different timing of task execution, the
|
|
|
|
|
+actual order will be different.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
|
|
|
|
|
+</B>Currently, changing the execution dynamically is not supported.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
|
|
|
|
|
+you need to reorder the queue – initialize the scheduler and re-add
|
|
|
|
|
+the tasks in a different order.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void
|
|
|
|
|
+deleteTask(Task& aTask)</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Deletes
|
|
|
|
|
+task aTask from the execution chain. The chain of remaining tasks is
|
|
|
|
|
+linked together (i.e</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">if
|
|
|
|
|
+original task chain is 1 → 2 → 3 → 4, deleting 3 will result in
|
|
|
|
|
+1 → 2 → 4).</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
|
|
|
|
|
+</B>it is not required to delete a task from the chain. A disabled
|
|
|
|
|
+task will not be executed anyway, but you save a few microseconds per
|
|
|
|
|
+scheduling pass by deleting it, since it is not even considered for
|
|
|
|
|
+execution.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">An
|
|
|
|
|
+example of proper use of this function would be running some sort of
|
|
|
|
|
+<B>initialize</B> task in the chain, and then deleting it from the
|
|
|
|
|
+chain since it only needs to run once.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void allowSleep(bool
|
|
|
|
|
+aState) </B>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Available
|
|
|
|
|
+in API only if compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
|
|
|
|
|
+enabled. Controls whether scheduler is allowed (<B>aState =true</B>),
|
|
|
|
|
+or not (<B>aState =false</B>) to put processor into IDLE sleep mode
|
|
|
|
|
+in case not tasks are scheduled to run.</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">The
|
|
|
|
|
+<B>default</B> behavior of scheduler upon creation is to allow sleep
|
|
|
|
|
+mode.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void enableAll()</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void disableAll()</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">enables
|
|
|
|
|
+and disables (respectively) all tasks in the chain. Convenient if
|
|
|
|
|
+your need to enable/disable majority of the tasks (i.e. disable all
|
|
|
|
|
+and then enable one).
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>Task&
|
|
|
|
|
+currentTask()<BR></B><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
|
|
|
|
|
+reference to the task, currently executing via <B>execute()</B> loop.
|
|
|
|
|
+Could be used by callback functions to identify which of the
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void execute()</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Executes
|
|
|
|
|
+one scheduling pass, including end-of-pass sleep. This function
|
|
|
|
|
+typically placed inside the <B>loop()</B> function of the sketch.
|
|
|
|
|
+Since <B>execute</B> exits after every pass, you can put additional
|
|
|
|
|
+statements after <B>execute</B> inside the <B>loop()</B>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
|
|
|
|
|
+<B>IMPLEMENTATION SCENARIOS AND IDEAS:</B></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<OL>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in"><B>EVENT DRIVEN
|
|
|
|
|
+ PROGRAMMING</B></P>
|
|
|
|
|
+</OL>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Each of the processes
|
|
|
|
|
+of your application becomes a separate and distinct programming area,
|
|
|
|
|
+which may or may not interact and control each other.
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Example:
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">In a plant watering
|
|
|
|
|
+system you need to measure soil humidity, control pump and display
|
|
|
|
|
+the results</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Each of the areas
|
|
|
|
|
+becomes a task:</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
|
|
|
|
|
+<B>tMeasure</B> (TMEASURE_INTERVAL*SECOND, -1,
|
|
|
|
|
+&measureCallback);<BR>Task <B>tWater</B>
|
|
|
|
|
+(TWATER_INTERVAL*SECOND, RETRIES, &waterCallback);<BR>Task
|
|
|
|
|
+<B>tDisplay</B> (TDISPLAY_INTERVAL*SECOND, -1, &displayCallback);
|
|
|
|
|
+<BR></FONT></FONT><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Scheduler
|
|
|
|
|
+</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>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Further, once you turn
|
|
|
|
|
+on the pump, you keep it running for TWATER_INTERVAL interval and
|
|
|
|
|
+then turn it off. Turning off a pump is also a task which only needs
|
|
|
|
|
+to run once for every time the pump is turned on:</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
|
|
|
|
|
+</FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2><B>tWaterOff</B></FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2>
|
|
|
|
|
+(WATERTIME*SECOND, 1,</FONT></FONT><FONT FACE="Courier New, monospace">
|
|
|
|
|
+&waterOffCallback);</FONT><BR><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in">Example of the callback
|
|
|
|
|
+function:</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
|
|
|
|
|
+waterOffCallback() {<BR> motorOff();<BR>
|
|
|
|
|
+tWater.enableDelayed();<BR>}</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>or</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
|
|
|
|
|
+waterCallback() {<BR> if (tWater.getIterations()) {</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
|
|
|
|
|
+If this is not the last iteration = turn the pump on<BR>
|
|
|
|
|
+motorOn();<BR> tWaterOff.set(parameters.watertime * SECOND, 1,
|
|
|
|
|
+&waterOffCallback);<BR> tWaterOff.enableDelayed();<BR>
|
|
|
|
|
+return;<BR> }</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
|
|
|
|
|
+We could not reach target humidity – something is wrong<BR>
|
|
|
|
|
+motorOff;<BR> taskManager.disableAll();<BR> tError.enable();<BR>}</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Your
|
|
|
|
|
+sample <B>setup</B>() and <B>loop</B>() (partially) are as follows. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Note:
|
|
|
|
|
+</B>please note that tWater is <B>not</B> activated during setup().
|
|
|
|
|
+It is activated by tMeasure callback once the watering conditions are
|
|
|
|
|
+met. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"> </FONT><FONT FACE="Courier New, monospace">setup()</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace">
|
|
|
|
|
+ ...</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
|
|
|
|
|
+<FONT FACE="Courier New, monospace">tWater.setIterations(parameters.retries);<BR>
|
|
|
|
|
+ tWaterOff.setInterval(parameters.watertime * SECOND);<BR><BR><BR>
|
|
|
|
|
+taskManager.init();<BR> taskManager.addTask(tMeasure);<BR>
|
|
|
|
|
+taskManager.addTask(tDisplay);<BR> taskManager.addTask(tWater);<BR>
|
|
|
|
|
+taskManager.addTask(tWaterOff);<BR> <BR> tMeasure.enable();<BR>
|
|
|
|
|
+tDisplay.enable();<BR><BR> currentHumidity =
|
|
|
|
|
+measureHumidity();<BR>}<BR><BR><BR>void loop ()<BR>{<BR>
|
|
|
|
|
+taskManager.execute();<BR>}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<OL START=2>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">“<FONT FACE="Times New Roman, serif"><B>NATIVE�
|
|
|
|
|
+ SUPPORT FOR FINITE STATE MACHINE</B></FONT></P>
|
|
|
|
|
+</OL>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Define
|
|
|
|
|
+“states� as callback function or functions. Each callback
|
|
|
|
|
+function executes activities specific to a “state� and then
|
|
|
|
|
+“transitions� to the next state by assigning next callback
|
|
|
|
|
+function to the task. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Transition
|
|
|
|
|
+from one state to the next is achieved by setting next callback
|
|
|
|
|
+function at the end of preceding one. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Note:
|
|
|
|
|
+</B>do not call the next callback function. Let the schedule take
|
|
|
|
|
+care of that during the next pass. (Thus letting other tasks run). </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Example:
|
|
|
|
|
+Blinking LED 2 times a second could be achieved this way</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">Task
|
|
|
|
|
+tLedBlinker (500, -1, &ledOnCallback);</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">Scheduler
|
|
|
|
|
+taskManager;</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">void
|
|
|
|
|
+ ledOnCallback() {</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> turnLedOn();</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.setCallback(&ledOffCallback);</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">void
|
|
|
|
|
+ ledOffCallback() {</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> turnLedOff();</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.setCallback(&ledOnCallback);</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">setup()
|
|
|
|
|
+{</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> taskManager.init();<BR>
|
|
|
|
|
+ taskManager.addTask(tLedBlinker);</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> </FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.enable();</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">loop
|
|
|
|
|
+() {</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> taskManager.execute();</FONT></P>
|
|
|
|
|
+<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>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Obviously
|
|
|
|
|
+the example is simple, but gives the idea of how the tasks could be
|
|
|
|
|
+used to go through states.</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<OL START=3>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>MULTIPLE
|
|
|
|
|
+ POSSIBLE CALLBACKS FOR TASK</B></FONT></P>
|
|
|
|
|
+</OL>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">There
|
|
|
|
|
+may be a need to select an option for callback function based on
|
|
|
|
|
+certain criteria, or randomly. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">You
|
|
|
|
|
+can achieve that by defining an array of callback function pointers
|
|
|
|
|
+and selecting one based on the criteria you need. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Example:
|
|
|
|
|
+when a robot detects an obstacle, it may go left, right backwards,
|
|
|
|
|
+etc. Each of the “directions� or “behaviors� are represented
|
|
|
|
|
+by a different callback function. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Another
|
|
|
|
|
+example of using multiple callbacks:</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">You
|
|
|
|
|
+may need to “initialize� variables for a particular task.</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">In
|
|
|
|
|
+this case, define a tasks with two callbacks:</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
|
|
|
|
|
+<B>tWork</B> (T_INTERVAL, -1, &workCallbackInit);</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">…</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
|
|
|
|
|
+ workCallbackInit() {</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
|
|
|
|
|
+do your initializationstuff here</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> </FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
|
|
|
|
|
+finally assigne the main callback function </FONT></FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.setCallback(&workCallback);</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
|
|
|
|
|
+workCallback() {</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
|
|
|
|
|
+main callback function</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> …</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">The
|
|
|
|
|
+task will initialize during first execution pass and switch to
|
|
|
|
|
+“regular� callback execution starting with second pass. There is
|
|
|
|
|
+a delay between first and second passes of the task (scheduling
|
|
|
|
|
+period, if defined). In order to execute the second pass immediately
|
|
|
|
|
+after initialization first pass, change the above code like this:</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
|
|
|
|
|
+ workCallbackInit() {</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
|
|
|
|
|
+do your initializationstuff here</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> </FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
|
|
|
|
|
+finally assigne the main callback function </FONT></FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.setCallback(&workCallback);</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.enable();</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">The
|
|
|
|
|
+task will run initialization first, then immediately second pass, and
|
|
|
|
|
+then switch to processing at regular intervals starting with a third
|
|
|
|
|
+pass. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<OL START=3>
|
|
|
|
|
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>INTERRUP-DRIVEN
|
|
|
|
|
+ EXECUTION SUPPORT </B></FONT>
|
|
|
|
|
+ </P>
|
|
|
|
|
+</OL>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">In
|
|
|
|
|
+case of interrupt-driven program flow, tasks could be scheduled to
|
|
|
|
|
+run once to request asynchronous execution (request), and then
|
|
|
|
|
+re-enabled (restarted) again with a different callback function to
|
|
|
|
|
+process the results. </FONT>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Example</B>:
|
|
|
|
|
+event driven distance calculation for ultrasonic pulses. EchoPin #6
|
|
|
|
|
+triggers pin change interrupts on rising and falling edges to
|
|
|
|
|
+determine the length of ultrasonic pulse.</FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>#include
|
|
|
|
|
+<DirectIO.h><BR>#include <TaskScheduler.h><BR>#include
|
|
|
|
|
+<PinChangeInt.h><BR><BR><BR>#define TRIGGERPIN 5<BR>#define
|
|
|
|
|
+ECHOPIN 6<BR><BR>Output<TRIGGERPIN>
|
|
|
|
|
+pTrigger;<BR>Input<ECHOPIN> pEcho;<BR><BR>Scheduler
|
|
|
|
|
+r;<BR><BR>Task tMeasure(1000, -1, &measureCallback);<BR>Task
|
|
|
|
|
+tDisplay(1000, -1, &displayCallback);<BR>Task tPing(0, 1,
|
|
|
|
|
+&pingCalcCallback);<BR><BR><BR>volatile bool pulseBusy =
|
|
|
|
|
+false;<BR>volatile bool pulseTimeout = false;<BR>volatile unsigned
|
|
|
|
|
+long pulseStart = 0;<BR>volatile unsigned long pulseStop =
|
|
|
|
|
+0;<BR>volatile unsigned long pingDistance = 0;<BR><BR><BR>void
|
|
|
|
|
+pingTrigger(unsigned long aTimeout) {<BR> if (pulseBusy) return; //
|
|
|
|
|
+do not trigger if in the middle of a pulse<BR> if (pEcho == HIGH)
|
|
|
|
|
+return; // do not trigger if ECHO pin is high<BR> <BR> pulseBusy =
|
|
|
|
|
+true;<BR> pulseTimeout = false;</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2><BR>
|
|
|
|
|
+ pTrigger = LOW;<BR> delayMicroseconds(4);<BR> pTrigger = HIGH;<BR><BR>
|
|
|
|
|
+ tPing.setInterval (aTimeout);<BR><BR> delayMicroseconds(10);<BR>
|
|
|
|
|
+pTrigger = LOW; <BR></FONT></FONT><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
|
|
|
|
|
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>tPing.restartDelayed();
|
|
|
|
|
+// timeout countdown starts now<BR></FONT></FONT><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
|
|
|
|
|
+will start the pulse clock on the rising edge of ECHO pin</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
|
|
|
|
|
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>PCintPort::attachInterrupt(ECHOPIN,
|
|
|
|
|
+&pingStartClock, RISING); <BR>}<BR><BR></FONT></FONT><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
|
|
|
|
|
+Start clock on the <B>rising</B> edge of the ultrasonic pulse<BR>void
|
|
|
|
|
+pingStartClock() {<BR> pulseStart = micros();<BR>
|
|
|
|
|
+PCintPort::detachInterrupt(ECHOPIN); // not sure this is necessary<BR>
|
|
|
|
|
+ PCintPort::attachInterrupt(ECHOPIN, &pingStopClock, FALLING); <BR>
|
|
|
|
|
+ tPing.restartDelayed();<BR>}<BR><BR>// Stop clock on the <B>falling</B>
|
|
|
|
|
+edge of the ultrasonic pulse<BR>void pingStopClock() {<BR> pulseStop
|
|
|
|
|
+= micros();<BR> PcintPort::detachInterrupt(ECHOPIN);</FONT></FONT></P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
|
|
|
|
|
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>pingDistance =
|
|
|
|
|
+pulseStop - pulseStart;<BR> pulseBusy = false;<BR> tPing.disable();
|
|
|
|
|
+// disable timeout<BR>}<BR></FONT></FONT><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
|
|
|
|
|
+Stop clock because of the timeout – the wave did not return<BR>void
|
|
|
|
|
+pingCalcCallback() {<BR> if (pulseBusy) {<BR> pingStopClock();<BR>
|
|
|
|
|
+ }<BR> pulseTimeout = true;<BR>}<BR><BR><BR><BR>// Initial measure
|
|
|
|
|
+callback sets the trigger<BR>void measureCallback() {<BR> if
|
|
|
|
|
+(pulseBusy) { // already measuring, try again<BR>
|
|
|
|
|
+tMeasure.enable();<BR> return;<BR> }<BR> pingTrigger(30); // 30
|
|
|
|
|
+milliseconds or max range of ~5.1 meters<BR>
|
|
|
|
|
+tMeasure.setCallback(&measureCallbackWait);<BR>}<BR></FONT></FONT><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
|
|
|
|
|
+Wait for the measurement to <BR>void measureCallbackWait() {<BR> if
|
|
|
|
|
+(pulseBusy) return;<BR> tMeasure.setCallback(&measureCallback);
|
|
|
|
|
+<BR>}<BR><BR><BR>bool state = true;<BR><BR>void displayCallback() {<BR>
|
|
|
|
|
+ char d[256];<BR> <BR> unsigned long cm = pingDistance * 17 / 100;
|
|
|
|
|
+// cm<BR> <BR> snprintf(d, 256, "pulseStart =
|
|
|
|
|
+%8lu\tpulseStop=%8lu\tdistance, cm=%8lu", pulseStart, pulseStop,
|
|
|
|
|
+cm);<BR> Serial.println(d);<BR> <BR>}<BR><BR>void setup() {<BR> //
|
|
|
|
|
+put your setup code here, to run once:<BR> <BR>
|
|
|
|
|
+Serial.begin(115200);<BR> <BR><BR> pTrigger = LOW;<BR> pEcho =
|
|
|
|
|
+LOW;<BR> <BR> r.init();<BR> r.addTask(tDisplay);<BR>
|
|
|
|
|
+r.addTask(tMeasure);<BR> r.addTask(tPing);<BR> <BR>
|
|
|
|
|
+r.enableAll();<BR> tPing.disable();<BR>}<BR><BR>void loop() {<BR>
|
|
|
|
|
+// put your main code here, to run repeatedly:<BR> r.execute();<BR>}<BR></FONT></FONT><BR>
|
|
|
|
|
+</P>
|
|
|
|
|
+</BODY>
|
|
|
|
|
+</HTML>
|