diff options
| author | Anatoli Arkhipenko <arkhipenko@hotmail.com> | 2015-09-22 17:03:03 -0400 |
|---|---|---|
| committer | Anatoli Arkhipenko <arkhipenko@hotmail.com> | 2015-09-22 17:03:03 -0400 |
| commit | 5d6cb5f626bd2b692071f4fe13a281fb15a45cd0 (patch) | |
| tree | e9053e5e2ed6db9a53094a58de1ec50e1cc64109 /documentation/TaskScheduler.htm | |
| parent | b17123e08aa575e2cc096c0b7818695c2f6cd163 (diff) | |
Issue1 fix
Diffstat (limited to 'documentation/TaskScheduler.htm')
| -rw-r--r-- | documentation/TaskScheduler.htm | 2542 |
1 files changed, 1271 insertions, 1271 deletions
diff --git a/documentation/TaskScheduler.htm b/documentation/TaskScheduler.htm index 3b37f1b..38b822a 100644 --- a/documentation/TaskScheduler.htm +++ b/documentation/TaskScheduler.htm @@ -1,1271 +1,1271 @@ -<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> +<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>
|
