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