Explorar o código

v1.8.4 bug fix and documentation update

 * bug fix: Task alignment with millis() for scheduling purposes should be done after OnEnable, not before. Especially since OnEnable method can change the interval
 * documentation update
Anatoli Arkhipenko %!s(int64=10) %!d(string=hai) anos
pai
achega
85f6d7b066
Modificáronse 5 ficheiros con 686 adicións e 69 borrados
  1. 46 43
      README
  2. BIN=BIN
      extras/TaskScheduler.doc
  3. 621 15
      extras/TaskScheduler.html
  4. 1 1
      library.properties
  5. 18 10
      src/TaskScheduler.h

+ 46 - 43
README

@@ -1,5 +1,5 @@
 Task Scheduler – cooperative multitasking for Arduino microcontrollers
-Version 1.8.3: 2015-11-05
+Version 1.8.4: 2015-11-17
   
 OVERVIEW:
 A lightweight implementation of cooperative multitasking (task scheduling) supporting:
@@ -13,33 +13,28 @@ A lightweight implementation of cooperative multitasking (task scheduling) suppo
 8. Support for Local Task Storage pointer (allowing use of same callback code for multiple tasks)
 
 Changelog:
-v1.0.0:
-    2015-02-24 - Initial release 
-    2015-02-28 - added delay() and disableOnLastIteration() functions
-    2015-03-25 - changed scheduler execute() function for a more precise delay calculation:
-                 1. Do not delay if any of the tasks ran (making request for immediate execution redundant)
-                 2. Delay is invoked only if none of the tasks ran 
-                 3. Delay is based on the min anticipated wait until next task _AND_ the runtime of execute function itself.
-    2015-05-11 - added  restart() and restartDelayed() functions to restart tasks which are on hold after running all iterations
-    2015-05-19 - completely removed  delay from the scheduler since there are no power saving there. using 1 ms sleep instead
+v1.8.4:
+    2015-11-15 - bug fix: Task alignment with millis() for scheduling purposes should be done after OnEnable, not before. Especially since OnEnable method can change the interval
+
+v1.8.3:
+    2015-11-05 - support for task activation on a status request with arbitrary interval and number of iterations (0 and 1 are still default values)
+    2015-11-05 - implement waitForDelayed() method to allow task activation on the status request completion delayed for one current interval
+    2015-11-09 - added callback methods prototypes to all examples for Arduino IDE 1.6.6 compatibility
+    2015-11-14 - added several constants to be used as task parameters for readability (e.g, TASK_FOREVER, TASK_SECOND, etc.)
+    2015-11-14 - significant optimization of the scheduler's execute loop, including millis() rollover fix option
+
+v1.8.2:
+    2015-10-27 - implement Local Task Storage Pointer (allow use of same callback code for different tasks)
+    2015-10-27 - bug: currentTask() method returns incorrect Task reference if called within OnEnable and OnDisable methods
+    2015-10-27 - protection against infinite loop in OnEnable (if enable() methods are called within OnEnable)
+    2015-10-29 - new currentLts() method in the scheduler class returns current task's LTS pointer in one call
 	
-v1.4.1:
-    2015-09-15 - more careful placement of AVR-specific includes for sleep functions (compatibility with DUE)
-                         sleep on idle run is no longer a default and should be explicitly compiled with _TASK_SLEEP_ON_IDLE_RUN defined
-						 
-v1.5.0:
-    2015-09-20 - access to currently executing task (for callback functions)
-    2015-09-20 - pass scheduler as a parameter to the task constructor to append the task to the end of the chain
-    2015-09-20 - option to create a task already enabled
+v1.8.1:
+    2015-10-22 - implement Task id and control points to support identification of failure points for watchdog timer logging
 	
-v1.5.1:
-    2015-09-21 - bug fix: incorrect handling of active tasks via set() and setIterations(). 
-		 		 Thanks to Hannes Morgenstern for catching this one
-				 
-v1.6.0:
-    2015-09-22 - revert back to having all tasks disable on last iteration.
-    2015-09-22 - deprecated disableOnLastIteration method as a result
-    2015-10-01 - made version numbers semver compliant (documentation only)
+v1.8.0:
+    2015-10-13 - support for status request objects allowing tasks waiting on requests
+    2015-10-13 - moved to a single header file to allow compilation control via #defines from the main sketch
 
 v1.7.0:
     2015-10-08 - introduced callback run counter - callback functions can branch on the iteration number. 
@@ -48,23 +43,31 @@ v1.7.0:
     2015-10-11 - introduced callback functions "on enable" and "on disable". On enable runs every time enable is called, on disable runs only if task was enabled
     2015-10-12 - new Task method: forceNextIteration() - makes next iteration happen immediately during the next pass regardless how much time is left
 
-v1.8.0:
-    2015-10-13 - support for status request objects allowing tasks waiting on requests
-    2015-10-13 - moved to a single header file to allow compilation control via #defines from the main sketch
+v1.6.0:
+    2015-09-22 - revert back to having all tasks disable on last iteration.
+    2015-09-22 - deprecated disableOnLastIteration method as a result
+    2015-10-01 - made version numbers semver compliant (documentation only)
 
-v1.8.1:
-    2015-10-22 - implement Task id and control points to support identification of failure points for watchdog timer logging
-	
-v1.8.2:
-    2015-10-27 - implement Local Task Storage Pointer (allow use of same callback code for different tasks)
-    2015-10-27 - bug: currentTask() method returns incorrect Task reference if called within OnEnable and OnDisable methods
-    2015-10-27 - protection against infinite loop in OnEnable (if enable() methods are called within OnEnable)
-    2015-10-29 - new currentLts() method in the scheduler class returns current task's LTS pointer in one call
+v1.5.1:
+    2015-09-21 - bug fix: incorrect handling of active tasks via set() and setIterations(). 
+		 		 Thanks to Hannes Morgenstern for catching this one
+				 
+v1.5.0:
+    2015-09-20 - access to currently executing task (for callback functions)
+    2015-09-20 - pass scheduler as a parameter to the task constructor to append the task to the end of the chain
+    2015-09-20 - option to create a task already enabled
 	
-v1.8.3:
-    2015-11-05 - support for task activation on a status request with arbitrary interval and number of iterations (0 and 1 are still default values)
-    2015-11-05 - implement waitForDelayed() method to allow task activation on the status request completion delayed for one current interval
-    2015-11-09 - added callback methods prototypes to all examples for Arduino IDE 1.6.6 compatibility
-    2015-11-14 - added several constants to be used as task parameters for readability (e.g, TASK_FOREVER, TASK_SECOND, etc.)
-    2015-11-14 - significant optimization of the scheduler's execute loop, including millis() rollover fix option
+v1.4.1:
+    2015-09-15 - more careful placement of AVR-specific includes for sleep functions (compatibility with DUE)
+                         sleep on idle run is no longer a default and should be explicitly compiled with _TASK_SLEEP_ON_IDLE_RUN defined
+						 
+v1.0.0:
+    2015-02-24 - Initial release 
+    2015-02-28 - added delay() and disableOnLastIteration() functions
+    2015-03-25 - changed scheduler execute() function for a more precise delay calculation:
+                 1. Do not delay if any of the tasks ran (making request for immediate execution redundant)
+                 2. Delay is invoked only if none of the tasks ran 
+                 3. Delay is based on the min anticipated wait until next task _AND_ the runtime of execute function itself.
+    2015-05-11 - added  restart() and restartDelayed() functions to restart tasks which are on hold after running all iterations
+    2015-05-19 - completely removed  delay from the scheduler since there are no power saving there. using 1 ms sleep instead
 

BIN=BIN
extras/TaskScheduler.doc


+ 621 - 15
extras/TaskScheduler.html

@@ -6,7 +6,7 @@
 	<META NAME="GENERATOR" CONTENT="LibreOffice 3.5  (Linux)">
 	<META NAME="CREATED" CONTENT="20150206;16300000">
 	<META NAME="CHANGEDBY" CONTENT="Anatoli Arkhipenko">
-	<META NAME="CHANGED" CONTENT="20151105;22050000">
+	<META NAME="CHANGED" CONTENT="20151115;15470000">
 	<META NAME="Info 1" CONTENT="">
 	<META NAME="Info 2" CONTENT="">
 	<META NAME="Info 3" CONTENT="">
@@ -28,7 +28,7 @@ Scheduler</B></FONT></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>cooperative
 multitasking for Arduino microcontrollers</B></P>
 <P CLASS="western" STYLE="margin-bottom: 0in; border-top: none; border-bottom: 1px solid #000000; border-left: none; border-right: none; padding-top: 0in; padding-bottom: 0.01in; padding-left: 0in; padding-right: 0in">
-<FONT SIZE=2 STYLE="font-size: 11pt"><B>Version 1.8.3: 2015-11-05</B></FONT></P>
+<FONT SIZE=2 STYLE="font-size: 11pt"><B>Version 1.8.4: 2015-11-17</B></FONT></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>OVERVIEW</B>:</P>
@@ -122,7 +122,7 @@ than the Scheduler's <B>execute</B>() method).</P>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
 <B>Below is the flowchart of a Task lifecycle:</B></P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><IMG SRC="TaskScheduler_html_m68472eb8.png" NAME="graphics1" ALIGN=BOTTOM WIDTH=664 HEIGHT=655 BORDER=0></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><IMG SRC="TaskScheduler_html.png" NAME="graphics1" ALIGN=BOTTOM WIDTH=664 HEIGHT=616 BORDER=0></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>TaskScheduler</B>
@@ -297,6 +297,611 @@ enabled by placing appropriate #define statements in front of the
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>TASK PRIORITY AND
+COOPERATIVE MULTITASKING:</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in">TaskScheduler <B>does
+not support</B> task priority functionality. I have been thinking a
+lot about it (especially since Symbian's Active Objects, which
+TaskScheduler is inspired by, support it), but decided against it.  
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">This is why:</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">1. Execution chains are
+simple and efficient. The main idea is to minimize scheduling
+overhead by Scheduler going through the chain. Implementing true
+priority would require looking ahead through the entire chain,
+ranking and aging tasks by priorities. It would slow the <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">execute()
+</FONT></FONT>loop significantly.</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">2. TaskScheduler is <B>NOT</B>
+a pre-emptive multi-tasking library. Nor is it a Real-Time OS. There
+is no way to break execution of one task in favor of another.
+Therefore callback methods require careful programming for
+cooperative behavior.</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">This has, however,
+significant benefits: you don't need to worry about concurrency
+inside the callback method, since only one callback method runs at a
+time, and could not be interrupted. All resources are yours for that
+period of time, noone can switch the value of variables (except
+interrupt functions of course...), etc. It is a stable and
+predictable environment, and it helps a lot with writing stable code.
+</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">A number of things
+could be done instead of priorities:</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">1. Schedule your
+critical tasks to run more frequently than the other tasks</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">. <BR>(Since you can
+control the interval, you could also change the task to run more or
+less frequently as the situation demands).</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">2. If one particular
+callback routine is critical, create a couple of tasks referring to
+the same callback and &quot;sprinkle&quot; them around the chain:</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">    <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Scheduler
+ts;</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">    <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task
+t1(20, TASK_FOREVER, &amp;callback1, &amp;ts);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">    <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task
+t2(1000, TASK_FOREVER, &amp;callback2, &amp;ts);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">    <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task
+t3(20, TASK_FOREVER, &amp;callback1, &amp;ts);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">    <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task
+t4(1000, TASK_FOREVER, &amp;callback4, &amp;ts);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">    <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t3.delay(10);</FONT></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>
+<P CLASS="western" STYLE="margin-bottom: 0in">Note that t1 and t3
+call the same callback method, and are shifted in time by 10 millis.
+So effectively callback1 will be called every 10 millis, but would be
+&quot;sandwiched&quot; between t2 and t4. 
+</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"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">3. Use short efficient
+callback methods written for cooperative multitasking.</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">What that means is:</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-left: 0.49in; margin-bottom: 0in">a)
+<B>DO NOT</B> use Arduino's  <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">delay()</FONT></FONT><FONT FACE="Andale Mono">
+</FONT>function. It is blocking and will hold the entire chain.
+Instead break the callback method into two, switch the callback
+method of the task where delay is necessary and delay the task by
+that number of millis. You get your delay, and other tasks get a
+chance to run:</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">instead
+of:</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">  
+ <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">delay(1000);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+more stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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">  
+  
+</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">do
+this:</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">  
+ <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback1() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&amp;callback2);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.delay(1000);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">  
+ <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback2() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+more stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&amp;callback1);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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"><BR>
+</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">b)
+Same goes to <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">pulseIn()</FONT></FONT>
+function. If you have to use it, set the timeout parameter such that
+it is not a default 1 second. PulseIn functionality could be achieved
+via pin interrupts, and that solution is non-blocking.</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">c)
+Do don run long loops (for or do/while) in you callback methods. Make
+the main arduino loop be the loop driver for you:</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">instead
+of:</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">  
+ <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback() {</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">  
+ 
+</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">for(int
+i=0; i&lt;1000; i++) {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+stuff // one loop action</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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"><BR>
+</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">do
+this:</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">  
+ <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task
+t1(TASK_IMMEDIATE, 1000, &amp;callback);</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">  
+  
+</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">int
+i = t1.getRunCounter() -1;</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+stuff // one loop action</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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"><BR>
+</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">or
+this:</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">  
+ <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task
+t1(TASK_IMMEDIATE, 1000, &amp;callback, true, &amp;t1On);</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">  
+ 
+</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">int
+i;</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">bool
+t1On() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">i
+= 0;</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">return
+true;</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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">  
+ 
+</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+stuff // one loop action</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">i++;</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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"><BR>
+</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" ALIGN=CENTER STYLE="margin-left: 0.49in; margin-bottom: 0in">
+<B>REMEMBER: you are already inside the loop - take advantage of it. </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">d)
+Break long running callback methods into several shorter ones, and
+pass control from one to the other via <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">setCallback()
+</FONT></FONT>method:</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">  
+ <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task
+t1(TASK_IMMEDIATE, TASK_FAREVER, &amp;callback);</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">  
+ 
+</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+do some stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&amp;callback_step2);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback_step2() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+do more stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&amp;callback_step3);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback_step3() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+do last part of the stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&amp;callback);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.delay(1000);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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"><BR>
+</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">This
+will execute all  parts of the callback function in three successive
+steps, sheduled immediately, but allowing other tasks in the cahin to
+run. Notince that task is scheduled to run immediately, and 1 second
+period is achieved by delaying the task for 1000 millis at the last
+step. 
+</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">Alternatively
+you could schedule the task to run every 1000 millis and use
+<FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">forceNextIteration()</FONT></FONT>
+method in steps 1 and 2 (but not 3!)</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">  
+ <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task
+t1(1000, TASK_FOREVER, &amp;callback);</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">  
+ 
+</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+do some stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&amp;callback_step2);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.forceNextIteration();</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback_step2() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+do more stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&amp;callback_step3);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.forceNextIteration();</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void
+callback_step3() {</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">...
+do last part of the stuff</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&amp;callback);</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="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</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"><BR>
+</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-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">e)
+Compile the library with <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt"><B>_TASK_TIMECRITICAL</B></FONT></FONT>
+enabled and check if your tasks are falling behind schedule. If they
+are - you need to optimize your code further (or maybe re-evaluate
+your schedule). If they are not - all is well and you don't need to
+do anything. E.g., I have a spider robot which needs to measure
+distance, control motors, and keep track of the angle via querying
+gyroscope and accelerometer every 10 ms. The idea was to flash
+onboard LED if any of the tasks fall behind. At 10 ms interval for
+the gyro the LED does not flash, which means none of the tasks are
+blocking the others from starting on time. 
+</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; page-break-after: avoid">
@@ -502,9 +1107,8 @@ is a task which was enabled and requires execution.
 <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>NOTE:
-</B><SPAN STYLE="font-weight: normal">if task</SPAN> being enabled is
-not assigned to a scheduler and is not part of execution chain, then
-task <B>will not</B> be enabled.</P>
+</B>if task being enabled is not assigned to a scheduler and is not
+part of execution chain, then task <B>will not</B> be enabled.</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>NOTE:
@@ -513,8 +1117,9 @@ task <B>will not</B> be enabled.</P>
 must return a value of <B>true</B> for task to be enabled. If
 <B>OnEnable</B> returns <B>false</B>, task remains disabled. 
 <B>OnEnable</B> is invoked every time <B>enable</B> is called,
-regardless if task is already enabled or not. 
-</P>
+regardless if task is already enabled or not. Alignment to current
+millis() is performed after <B>OnEnable</B> exits, so any changes to
+the interval inside <B>OnEnable</B> is taken into consideration.</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>NOTE:</B>
@@ -703,8 +1308,7 @@ and number of iterations.
 default <B>waitForDelayed() </B>sets tasks interval to a supplied
 value or (if omitted or zero) keeps the current interval, so delayed
 execution will take place when the event happens.  It also sets the
-number of <B>iterations to 1</B><SPAN STYLE="font-weight: normal"> by
-default if not supplied</SPAN>.  
+number of <B>iterations to 1</B> by default if not supplied.  
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">When
 Status Request object completes, all tasks waiting on it are executed
@@ -972,10 +1576,9 @@ statements after <B>execute</B> inside the <B>loop()</B>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>bool isOverrun()</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, this method returns <B>true</B><SPAN STYLE="font-weight: normal">
-if currently invoked task has overrun its scheduled start time when
-it was invoked. Returns </SPAN><B>false</B><SPAN STYLE="font-weight: normal">
-if task has been invoked according to schedule.</SPAN></P>
+enabled, this method returns <B>true</B> if currently invoked task
+has overrun its scheduled start time when it was invoked. Returns
+<B>false</B> if task has been invoked according to schedule.</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>
@@ -2145,5 +2748,8 @@ time examples of TaskScheduler are available here:</FONT></FONT></P>
 </OL>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
+<DIV TYPE=FOOTER>
+	<P STYLE="margin-top: 0.35in; margin-bottom: 0in">	<SDFIELD TYPE=PAGE SUBTYPE=RANDOM FORMAT=ARABIC>5</SDFIELD></P>
+</DIV>
 </BODY>
-</HTML>
+</HTML>

+ 1 - 1
library.properties

@@ -1,5 +1,5 @@
 name=TaskScheduler
-version=1.8.3
+version=1.8.4
 author=Anatoli Arkhipenko <arkhipenko@hotmail.com>
 maintainer=Anatoli Arkhipenko <arkhipenko@hotmail.com>
 sentence=A light-weight cooperative multitasking library for arduino microcontrollers.

+ 18 - 10
src/TaskScheduler.h

@@ -1,4 +1,4 @@
-// Cooperative multitasking library for Arduino version 1.8.2
+// Cooperative multitasking library for Arduino version 1.8.4
 // Copyright (c) 2015 Anatoli Arkhipenko
 //
 // Changelog:
@@ -57,6 +57,10 @@
 //    2015-11-09 - added callback methods prototypes to all examples for Arduino IDE 1.6.6 compatibility
 //    2015-11-14 - added several constants to be used as task parameters for readability (e.g, TASK_FOREVER, TASK_SECOND, etc.)
 //    2015-11-14 - significant optimization of the scheduler's execute loop, including millis() rollover fix option
+//
+// v1.8.4:
+//    2015-11-15 - bug fix: Task alignment with millis() for scheduling purposes should be done after OnEnable, not before. Especially since OnEnable method can change the interval
+//    2015-11-16 - further optimizations of the task scheduler execute loop
 
 
 /* ============================================
@@ -379,7 +383,6 @@ void Task::setIterations(long aIterations) {
 void Task::enable() {
 	if (iScheduler) { // activation without active scheduler does not make sense
 		iRunCounter = 0;
-		iPreviousMillis = millis() - iInterval;
 		if (iOnEnable && !iInOnEnable) {
 			Task *current = iScheduler->iCurrent;
 			iScheduler->iCurrent = this;
@@ -391,6 +394,7 @@ void Task::enable() {
 		else {
 			iEnabled = true;
 		}
+		iPreviousMillis = millis() - iInterval;
 	}
 }
 
@@ -569,6 +573,7 @@ void Scheduler::execute() {
 	bool		idleRun = true;
 #endif
 	unsigned long targetMillis;
+	register unsigned long m, i, p;
 	
 	iCurrent = iFirst;
 
@@ -585,13 +590,16 @@ void Scheduler::execute() {
 					iCurrent->disable();
 					break;
 				}
-	#ifdef  _TASK_STATUS_REQUEST
+				m = millis();
+				p = iCurrent->iPreviousMillis;
+				i = iCurrent->iInterval;
+				#ifdef  _TASK_STATUS_REQUEST
 	// If StatusRequest object was provided, and still pending, and task is waiting, this task should not run
 	// Otherwise, continue with execution as usual.  Tasks waiting to StatusRequest need to be rescheduled according to 
 	// how they were placed into waiting state (waitFor or waitForDelayed)
 				if ( iCurrent->iWaiting ) {
 					if ( (iCurrent->iStatusRequest)->pending() ) break;
-					iCurrent->iPreviousMillis = (iCurrent->iWaiting == _TASK_SR_NODELAY) ? millis()-iCurrent->iInterval : millis();
+					iCurrent->iPreviousMillis = (iCurrent->iWaiting == _TASK_SR_NODELAY) ? m - i : m;
 					iCurrent->iWaiting = 0;
 				}
 	#endif
@@ -607,20 +615,19 @@ void Scheduler::execute() {
 	//  since targetMillis (65) < iPreviousMillis (65000), rollover fix kicks in:
 	//  iPreviousMillis(65000) > millis(65500) - iInterval(600) = 64900 - task will not be scheduled
 	
-				targetMillis = iCurrent->iPreviousMillis + iCurrent->iInterval;
+				targetMillis = p + i;
 	#ifdef _TASK_ROLLOVER_FIX
-				if ( targetMillis < iCurrent->iPreviousMillis ) {  // targetMillis rolled over!
-					if ( iCurrent->iPreviousMillis > ( millis() - iCurrent->iInterval) )  break;
+				if ( targetMillis < p ) {  // targetMillis rolled over!
+					if ( p > ( m - i) )  break;
 				}
 				else
 	#endif
-					if ( targetMillis > millis() ) break;
+					if ( targetMillis > m ) break;
 	
-				iCurrent->iPreviousMillis = targetMillis;
 	#ifdef _TASK_TIMECRITICAL
 	// Updated_previous+current interval should put us into the future, so iOverrun should be positive or zero. 
 	// If negative - the task is behind (next execution time is already in the past) 
-				iCurrent->iOverrun = (long) (iCurrent->iPreviousMillis + iCurrent->iInterval - millis());
+				iCurrent->iOverrun = (long) ( targetMillis - m + i );
 	#endif
 				if ( iCurrent->iIterations > 0 ) iCurrent->iIterations--;  // do not decrement (-1) being a signal of never-ending task
 				iCurrent->iRunCounter++;
@@ -630,6 +637,7 @@ void Scheduler::execute() {
 					idleRun = false;
 	#endif
 				}
+				iCurrent->iPreviousMillis = targetMillis;
 			}
 		} while (0); //guaranteed single run - allows use of "break" to exit 
 		iCurrent = iCurrent->iNext;