浏览代码

Version 1.8.3 number of addtions and improvements

 * support for task activation on a status request with arbitrary interval and number of iterations (0 and 1 are still default values)
 * implement waitForDelayed() method to allow task activation on the status request completion delayed for one current interval
 * added callback methods prototypes to all examples for Arduino IDE 1.6.6 compatibility
 * added several constants to be used as task parameters for readability (e.g, TASK_FOREVER, TASK_SECOND, etc.)
 * significant optimization of the scheduler's execute loop, including millis() rollover fix option
Anatoli Arkhipenko 10 年之前
父节点
当前提交
dc152db48e

+ 9 - 3
README

@@ -1,7 +1,6 @@
 Task Scheduler – cooperative multitasking for Arduino microcontrollers
-Version 1.8.2: 2015-10-29
- 
- 
+Version 1.8.3: 2015-11-05
+  
 OVERVIEW:
 A lightweight implementation of cooperative multitasking (task scheduling) supporting:
 1. Periodic task execution (with dynamic execution period in milliseconds)
@@ -62,3 +61,10 @@ v1.8.2:
     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.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
+

+ 17 - 12
examples/Scheduler_example/Scheduler_example.ino

@@ -13,10 +13,16 @@
  
 #include <TaskScheduler.h>
 
+// Callback methods prototypes
+void t1Callback();
+void t2Callback();
+void t3Callback();
+
+//Tasks
 Task t4();
 Task t1(2000, 10, &t1Callback);
-Task t2(3000, -1, &t2Callback);
-Task t3(5000, -1, &t3Callback);
+Task t2(3000, TASK_FOREVER, &t2Callback);
+Task t3(5000, TASK_FOREVER, &t3Callback);
 
 Scheduler runner;
 
@@ -26,8 +32,8 @@ void t1Callback() {
     Serial.println(millis());
     
     if (t1.isFirstIteration()) {
-       t3.enable();
-       runner.addTask(t3);
+      runner.addTask(t3);
+      t3.enable();
       Serial.println("t1: enabled t3 and added to the chain");
     }
     
@@ -55,12 +61,6 @@ void setup () {
   Serial.begin(115200);
   Serial.println("Scheduler TEST");
   
-  
-  t1.enable();
-  Serial.println("Enabled t1");
-  t2.enable();
-  Serial.println("Enabled t2");
-  
   runner.init();
   Serial.println("Initialized scheduler");
   
@@ -69,11 +69,16 @@ void setup () {
   
   runner.addTask(t2);
   Serial.println("added t2");
-  
+
   delay(5000);
+  
+  t1.enable();
+  Serial.println("Enabled t1");
+  t2.enable();
+  Serial.println("Enabled t2");
 }
 
 
 void loop () {
   runner.execute();
-}
+}

+ 14 - 7
examples/Scheduler_example2/Scheduler_example2.ino

@@ -2,11 +2,16 @@
 #include <TaskScheduler.h>
 
 Scheduler runner;
+// Callback methods prototypes
+void t1Callback();
+void t2Callback();
+void t3Callback(); 
 
+// Tasks
 Task t4();
 Task t1(2000, 10, &t1Callback, &runner, true);  //adding task to the chain on creation
-Task t2(3000, -1, &t2Callback, &runner, true);  //adding task to the chain on creation
-Task t3(5000, -1, &t3Callback);
+Task t2(3000, TASK_FOREVER, &t2Callback, &runner, true);  //adding task to the chain on creation
+Task t3(5000, TASK_FOREVER, &t3Callback);
 
 // Test
 // Initially only tasks 1 and 2 are enabled
@@ -18,6 +23,8 @@ Task t3(5000, -1, &t3Callback);
 // Task1 disables Task3 on its last iteration and changed Task2 to run every 1/2 seconds
 // Because Task2 interval is shorter than Scheduler default tick, loop() executes ecery 1/2 seconds now
 // At the end Task2 is the only task running every 1/2 seconds
+//
+// NOTE that t1 and t2 are affected by the delay() function in the setup() method and are scheduled immediately twice to "catch up" with millis().
 
 
 
@@ -28,8 +35,8 @@ void t1Callback() {
     Serial.println(millis());
     
     if (t1.isFirstIteration()) {
-       t3.enable();
-       runner.addTask(t3);
+      runner.addTask(t3);
+      t3.enable();
       Serial.println("t1: enabled t3 and added to the chain");
     }
     
@@ -65,6 +72,6 @@ void loop () {
   
   runner.execute();
   
-  Serial.println("Loop ticks at: ");
-  Serial.println(millis());
-}
+//  Serial.println("Loop ticks at: ");
+//  Serial.println(millis());
+}

+ 13 - 4
examples/Scheduler_example3/Scheduler_example3.ino

@@ -1,7 +1,7 @@
 /**
  * TaskScheduler Test of OnEnable and OnDisable methods and illustration of using wrapper tasks for timout purposes
  *
- * 	A wrapper task runs every 30 seconds and initiates the test case
+ * 	A wrapper task runs every 10 seconds and initiates the test case
  * 	Another task is run once for 5 seconds, and serves as a LED blinking timeout - 5 seconds
  * 	Finally, a dedicated task which controls LED is running periodically until stopped, and makes the LED blink with 0.5 to 1 second interval. 
  *
@@ -14,9 +14,17 @@
 
 Scheduler ts;
 
-Task tWrapper(30000L, -1, &WrapperCallback, &ts, true);
-Task tBlink(5000, 1, NULL, &ts, false, &BlinkOnEnable, &BlinkOnDisable);
-Task tLED(0, -1, NULL, &ts, false, NULL, &LEDOff);
+// Callback methods prototypes
+void WrapperCallback();
+bool BlinkOnEnable();
+void BlinkOnDisable();
+void LEDOn();
+void LEDOff();
+
+// Tasks
+Task tWrapper(10000L, TASK_FOREVER, &WrapperCallback, &ts, true);
+Task tBlink(5000, TASK_ONCE, NULL, &ts, false, &BlinkOnEnable, &BlinkOnDisable);
+Task tLED(0, TASK_FOREVER, NULL, &ts, false, NULL, &LEDOff);
 
 void WrapperCallback() {
 	tBlink.restartDelayed(); // LED blinking is initiated
@@ -61,6 +69,7 @@ void LEDOff () {
 
 void setup() {
 // put your setup code here, to run once:
+  pinMode(LEDPIN, OUTPUT);
 }
 
 void loop() {

+ 10 - 2
examples/Scheduler_example4_StatusRequest/Scheduler_example4_StatusRequest.ino

@@ -13,7 +13,15 @@ StatusRequest st;
 
 Scheduler ts; 
 
-Task t1(5000, 1, &Callback1, &ts, true, NULL, &Disable1);
+// Callback methods prototypes
+void Callback1();
+void Disable1();
+void Callback2();
+void Callback3();
+void PrepareStatus();
+
+// Tasks
+Task t1(5000, TASK_ONCE, &Callback1, &ts, true, NULL, &Disable1);
 Task t2(&Callback2, &ts);
 Task t3(&Callback3, &ts);
 
@@ -77,4 +85,4 @@ void loop() {
 
   ts.execute();
 
-}
+}

+ 17 - 10
examples/Scheduler_example5_StatusRequest/Scheduler_example5_StatusRequest.ino

@@ -7,22 +7,29 @@
 
 #define _TASK_SLEEP_ON_IDLE_RUN
 #define _TASK_STATUS_REQUEST
-
 #include <TaskScheduler.h>
 
-
-
-
 StatusRequest measure;
 
 Scheduler ts; 
 
-Task tCycle(10000, -1, &CycleCallback, &ts, true);
-Task tMeasure(1000, 1, &MeasureCallback, &ts, false, &MeasureEnable, &MeasureDisable);
+// Callback methods prototypes
+void CycleCallback();
+void MeasureCallback(); 
+bool MeasureEnable();
+void MeasureDisable();
+void CalcCallback();
+void S1Callback(); bool S1Enable();
+void S2Callback(); bool S2Enable();
+void S3Callback(); bool S3Enable();
+
+// Tasks
+Task tCycle(10000, TASK_FOREVER, &CycleCallback, &ts, true);
+Task tMeasure(1000, TASK_ONCE, &MeasureCallback, &ts, false, &MeasureEnable, &MeasureDisable);
 Task tCalculate(&CalcCallback, &ts);
-Task tSensor1(0, 1, &S1Callback, &ts, false, &S1Enable);
-Task tSensor2(0, 1, &S2Callback, &ts, false, &S2Enable);
-Task tSensor3(0, 1, &S3Callback, &ts, false, &S3Enable);
+Task tSensor1(0, TASK_ONCE, &S1Callback, &ts, false, &S1Enable);
+Task tSensor2(0, TASK_ONCE, &S2Callback, &ts, false, &S2Enable);
+Task tSensor3(0, TASK_ONCE, &S3Callback, &ts, false, &S3Enable);
 
 
 long distance, d1, d2, d3;
@@ -162,4 +169,4 @@ void loop() {
   
   ts.execute();
 
-}
+}

+ 8 - 3
examples/Scheduler_example6_IDLE/Scheduler_example6_IDLE.ino

@@ -38,8 +38,13 @@ C1 is scenario 2) is much higher than in scenario 1) because processor is put to
 
 Scheduler ts;
 
-Task c(10, -1, &Count, &ts);
-Task t(10000, 1, NULL, &ts, true, &tOn, &tOff);
+// Callback methods prototypes
+void Count();
+bool tOn(); void tOff();
+
+// Tasks
+Task c(10, TASK_FOREVER, &Count, &ts);
+Task t(10000, TASK_ONCE, NULL, &ts, true, &tOn, &tOff);
 
 
 volatile unsigned long c1, c2;
@@ -74,4 +79,4 @@ void loop() {
   // put your main code here, to run repeatedly:
   ts.execute();
   c1++;
-}
+}

+ 9 - 5
examples/Scheduler_example7_WDT/Scheduler_example7_WDT.ino

@@ -18,14 +18,18 @@
 
 Scheduler ts;
 
+// Callback methods prototypes
+void TaskCB(); 
+void HB(); bool HBOn(); void HBOff();
+
 // Three tasks emulating accidental infinite loop
-Task tTask1(1000, -1, &TaskCB, &ts, true);
-Task tTask2(1000, -1, &TaskCB, &ts, true);
-Task tTask3(1000, -1, &TaskCB, &ts, true);
+Task tTask1(TASK_SECOND, TASK_FOREVER, &TaskCB, &ts, true);
+Task tTask2(TASK_SECOND, TASK_FOREVER, &TaskCB, &ts, true);
+Task tTask3(TASK_SECOND, TASK_FOREVER, &TaskCB, &ts, true);
 
 // Heartbeat task - resetting the watchdog timer periodically
 // Initiates WDT on enable, and deactivates it on disable
-Task tHB(500, -1, &HB, &ts, false, &HBOn, &HBOff);
+Task tHB(500, TASK_FOREVER, &HB, &ts, false, &HBOn, &HBOff);
 
 /**
  * Emulating task callback function
@@ -125,4 +129,4 @@ void setup() {
  */
 void loop() {
   ts.execute();
-}
+}

+ 10 - 5
examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino

@@ -23,16 +23,21 @@
 
 Scheduler ts;
 
+// Callback methods prototypes
+void Calculate(); bool CalcOn();
+bool WrapperOn(); void WrapperOff(); 
+
+// Tasks
 // Calculator tasks.
 // Note that all three tasks use the same callback methods
 // They will be updating specific variables based on the
 // Locat Task Storage pointers 
-Task t1(1000, -1, &Calculate, &ts, false, &CalcOn); 
-Task t2(1000, -1, &Calculate, &ts, false, &CalcOn); 
-Task t3(1000, -1, &Calculate, &ts, false, &CalcOn);
+Task t1(TASK_SECOND, TASK_FOREVER, &Calculate, &ts, false, &CalcOn); 
+Task t2(TASK_SECOND, TASK_FOREVER, &Calculate, &ts, false, &CalcOn); 
+Task t3(TASK_SECOND, TASK_FOREVER, &Calculate, &ts, false, &CalcOn);
 // add more calc tasks here if necessary
 
-Task tWrapper(5000, 1, NULL, &ts, false, &WrapperOn, &WrapperOff); 
+Task tWrapper(5*TASK_SECOND, TASK_ONCE, NULL, &ts, false, &WrapperOn, &WrapperOff); 
 
 // The below structure is an object referenced by LTS pointer
 typedef struct {
@@ -139,4 +144,4 @@ void setup() {
 
 void loop() {
   ts.execute();
-}
+}

二进制
extras/TaskScheduler.doc


+ 143 - 51
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="20151029;23230000">
+	<META NAME="CHANGED" CONTENT="20151105;22050000">
 	<META NAME="Info 1" CONTENT="">
 	<META NAME="Info 2" CONTENT="">
 	<META NAME="Info 3" CONTENT="">
@@ -15,8 +15,8 @@
 	<!--
 		@page { margin: 0.79in }
 		P { margin-bottom: 0.08in; direction: ltr; color: #000000; widows: 0; orphans: 0 }
-		P.western { font-family: "Liberation Serif", "MS PMincho", serif; font-size: 12pt; so-language: en-US }
-		P.cjk { font-family: "WenQuanYi Micro Hei", "MS Mincho"; font-size: 12pt }
+		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 }
 		A:link { color: #0000ff }
 	-->
@@ -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.2: 2015-10-27</B></FONT></P>
+<FONT SIZE=2 STYLE="font-size: 11pt"><B>Version 1.8.3: 2015-11-05</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.png" NAME="graphics1" ALIGN=BOTTOM WIDTH=664 HEIGHT=690 BORDER=0></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"><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>TaskScheduler</B>
@@ -276,6 +276,19 @@ LTS pointer to the appropriate pointer type.
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
+<P CLASS="western" STYLE="margin-bottom: 0in">#define
+<B>_TASK_ROLLOVER_FIX</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in">…will compile
+TaskScheduler with support for millis() rollover approximately every
+47 days. Only required if you plan for your sketch to run for
+extended amount of time (over 47 days).</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">The problem here is
+when scheduler calculates next execution time for a task, a rollover
+may place next execution time “in the past” and cause task to be
+invoked incorrectly once every 47 days. 
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>NOTE: </B>above
 parameters are<B> DISABLED </B>by default, and need to be explicitly
 enabled by placing appropriate #define statements in front of the
@@ -488,7 +501,13 @@ 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-left: 0.49in; margin-bottom: 0in"><B>Note:
+<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>
+<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>enable() invokes task’s <B>OnEnable</B> method (if not NULL)
 <B>immediately</B>, which can prepare task for execution. <B>OnEnable</B>
 must return a value of <B>true</B> for task to be enabled. If
@@ -662,17 +681,38 @@ METHODS:</B></P>
 <BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
-<B>void waitFor(StatusRequest* aStatusRequest);</B></P>
+<B>void waitFor(StatusRequest* aStatusRequest, unsigned long
+aInterval = 0, long aIterations = 1)</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<B>void waitForDelayed(StatusRequest* aStatusRequest, unsigned long
+aInterval = 0, long aIterations = 1)</B></P>
 <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
 <BR>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
-compiled with support for Status Requests, this method makes task
+compiled with support for Status Requests, these methods make task
 wait for the completion of <B>aStatusRequest</B> event. 
 </P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>waitFor()
-</B>sets tasks interval to <B>0 (zero)</B> for immediate execution
-when event happens, and also sets the number of <B>iterations to 1</B>.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">By
+default <B>waitFor() </B>sets tasks interval to <B>0 (zero)</B> for
+immediate execution when event happens, and also sets the number of
+<B>iterations to 1</B>. However, you can specify different interval
+and number of iterations. 
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">By
+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>.  
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">When
+Status Request object completes, all tasks waiting on it are executed
+during next scheduling pass. Tasks waiting via <B>waitFor</B>()
+method are executed immediately. Tasks waiting via <B>waitForDelayed</B>()
+method are activated, but executed after current or supplied interval
+delay. 
+</P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
 aStatusRequest</B> should be “activated” by calling <B>setWaiting()
 </B>method before making a task wait on it. Otherwise, the task will
@@ -703,8 +743,8 @@ a StatusReqeust object this Task was waiting on.
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>TASK ID, CONTROL
-POINTS METHODS:</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<B>TASK ID, CONTROL POINTS METHODS:</B></P>
 <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
 <BR>
 </P>
@@ -929,6 +969,13 @@ 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-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>
 <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>
@@ -955,7 +1002,7 @@ status of “completed” on creation.
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>void
-setWaiting(unsigned int aCount)</B></P>
+setWaiting(unsigned int aCount = 1)</B></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Activates
 Status Request object. By default each object is set to wait on one
 event only, however, if <B>aCount</B> is supplied, Status Request can
@@ -1023,6 +1070,46 @@ completion of a request.</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>CONSTANTS:</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<B>TASK_SECOND	(1000)</B></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">Task
+interval of 1 second</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<B>TASK_MINUTE	(60000)</B></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">Task
+interval of 1 minute</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<B>TASK_HOUR		(3600000)</B></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">Task
+interval of 1 hour</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<B>TASK_FOREVER	(-1)</B></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">Task
+number of iterations for infinite number of iterations</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<B>TASK_ONCE		(1)</B></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">Task
+single iteration</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<B>TASK_IMMEDIATE	(0)</B></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">Task
+interval for immediate execution</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-before: always; page-break-after: avoid">
 <B>IMPLEMENTATION SCENARIOS AND IDEAS:</B></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
@@ -1048,11 +1135,11 @@ 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,
+<B>tMeasure</B> (TMEASURE_INTERVAL*SECOND, TASK_FOREVER,
 &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>
+<B>tDisplay</B> (TDISPLAY_INTERVAL*SECOND, TASK_FOREVER,
+&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>
@@ -1065,7 +1152,7 @@ to run once for every time the pump is turned on:</P>
 </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">
+(WATERTIME*SECOND, TASK_ONCE,</FONT></FONT><FONT FACE="Courier New, monospace">
 &amp;waterOffCallback);</FONT><BR><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in">Example of the callback
@@ -1084,9 +1171,9 @@ tWater.enableDelayed();<BR>}</FONT></FONT></P>
 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>
+motorOn();<BR>      tWaterOff.set(parameters.watertime * TASK_SECOND,
+TASK_ONCE, &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>
@@ -1146,7 +1233,7 @@ Blinking LED 2 times a second could be achieved this way</FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Scheduler
 ts;</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
-tLedBlinker (500, -1, &amp;ledOnCallback, &amp;ts, true);</FONT></FONT></P>
+tLedBlinker (500, TASK_FOREVER, &amp;ledOnCallback, &amp;ts, 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="Courier New, monospace"><FONT SIZE=2>void
@@ -1212,7 +1299,7 @@ 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>
+<B>tWork</B> (T_INTERVAL, TASK_FOREVER, &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>
@@ -1290,16 +1377,17 @@ determine the length of ultrasonic pulse.</FONT></P>
 &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, &amp;r,
-true);<BR>Task  tDisplay(1000, -1, &amp;displayCallback, &amp;r,
-true);<BR>Task  tPing(0, 1, &amp;pingCalcCallback, &amp;r,
-false);<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>
+r;<BR><BR>Task  tMeasure(TASK_SECOND, TASK_FOREVER, &amp;measureCallback,
+&amp;r, true);<BR>Task  tDisplay(TASK_SECOND, TASK_FOREVER,
+&amp;displayCallback, &amp;r, true);<BR>Task  tPing(TASK_IMMEDIATE,
+TASK_ONCE, &amp;pingCalcCallback, &amp;r, false);<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> 
@@ -1396,12 +1484,13 @@ ts;</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>Task
-tWrapper(30000, -1, &amp;WrapperCallback, &amp;ts, true);</FONT></FONT></P>
+tWrapper(30000, TASK_FOREVER, &amp;WrapperCallback, &amp;ts, true);</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
-tBlink(5000, 1, NULL, &amp;ts, false, &amp;BlinkOnEnable,
+tBlink(5000, TASK_ONCE, NULL, &amp;ts, false, &amp;BlinkOnEnable,
 &amp;BlinkOnDisable);</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
-tLED(0, -1, NULL, &amp;ts, false, NULL, &amp;LEDOff);</FONT></FONT></P>
+tLED(TASK_IMMEDIATE, TASK_FOREVER, NULL, &amp;ts, false, NULL,
+&amp;LEDOff);</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
@@ -1582,18 +1671,21 @@ ts; </FONT></FONT>
 <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>Task
-tCycle(10000, -1, &amp;CycleCallback, &amp;ts, true);</FONT></FONT></P>
+tCycle(10000, TASK_FOREVER, &amp;CycleCallback, &amp;ts, true);</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
-tMeasure(1000, 1, &amp;MeasureCallback, &amp;ts, false,
-&amp;MeasureEnable, &amp;MeasureDisable);</FONT></FONT></P>
+tMeasure(TASK_SECOND, TASK_ONCE, &amp;MeasureCallback, &amp;ts,
+false, &amp;MeasureEnable, &amp;MeasureDisable);</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
 tCalculate(&amp;CalcCallback, &amp;ts);</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
-tSensor1(0, 1, &amp;S1Callback, &amp;ts, false, &amp;S1Enable);</FONT></FONT></P>
+tSensor1(TASK_IMMEDIATE, TASK_ONCE, &amp;S1Callback, &amp;ts, false,
+&amp;S1Enable);</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
-tSensor2(0, 1, &amp;S2Callback, &amp;ts, false, &amp;S2Enable);</FONT></FONT></P>
+tSensor2(TASK_IMMEDIATE, TASK_ONCE, &amp;S2Callback, &amp;ts, false,
+&amp;S2Enable);</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
-tSensor3(0, 1, &amp;S3Callback, &amp;ts, false, &amp;S3Enable);</FONT></FONT></P>
+tSensor3(TASK_IMMEDIATE, TASK_ONCE, &amp;S3Callback, &amp;ts, false,
+&amp;S3Enable);</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>
@@ -1973,13 +2065,13 @@ that both tasks refer to the same callback methods)</FONT></FONT></P>
 </P>
 <P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
 <FONT FACE="Courier New, monospace"><FONT SIZE=2>Scheduler ts;</FONT></FONT></P>
-<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
-<FONT FACE="Courier New, monospace"><FONT SIZE=2>Task t1(100, -1,
-&amp;Measure, &amp;ts, false, &amp;MeasureOn); </FONT></FONT>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2><SPAN LANG="">Task
+t1(100, </SPAN>TASK_FOREVER<SPAN LANG="">, &amp;Measure, &amp;ts,
+false, &amp;MeasureOn); </SPAN></FONT></FONT>
 </P>
-<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
-<FONT FACE="Courier New, monospace"><FONT SIZE=2>Task t2(100, -1,
-&amp;Measure, &amp;ts, false, &amp;MeasureOn); </FONT></FONT>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2><SPAN LANG="">Task
+t2(100, </SPAN>TASK_FOREVER<SPAN LANG="">, &amp;Measure, &amp;ts,
+false, &amp;MeasureOn); </SPAN></FONT></FONT>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
 </P>
@@ -2047,9 +2139,9 @@ information and implementation options.</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Real
 time examples of TaskScheduler are available here:</FONT></FONT></P>
 <OL>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/"><FONT FACE="Courier New, monospace"><FONT SIZE=2>http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/</FONT></FONT></A></U></FONT></P>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/"><FONT FACE="Courier New, monospace"><FONT SIZE=2>http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/</FONT></FONT></A></U></FONT></P>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider"><FONT FACE="Courier New, monospace"><FONT SIZE=2>http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider</FONT></FONT></A></U></FONT></P>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/"><FONT FACE="Courier New, monospace">http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/</FONT></A></U></FONT></P>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/"><FONT FACE="Courier New, monospace">http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/</FONT></A></U></FONT></P>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider"><FONT FACE="Courier New, monospace">http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider</FONT></A></U></FONT></P>
 </OL>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>

+ 14 - 0
keywords.txt

@@ -52,6 +52,7 @@ pending	KEYWORD2
 completed	KEYWORD2
 getStatus	KEYWORD2
 waitFor	KEYWORD2
+waitForDelayed	KEYWORD2
 getStatusRequest	KEYWORD2
 setId	KEYWORD2
 getId	KEYWORD2
@@ -59,8 +60,21 @@ setControlPoint	KEYWORD2
 getControlPoint	KEYWORD2
 setLtsPointer	KEYWORD2
 getLtsPointer	KEYWORD2
+isOverrun	KEYWORD2
 
 #######################################
 # Constants (LITERAL1)
+TASK_SECOND	LITERAL1
+TASK_MINUTE	LITERAL1
+TASK_HOUR	LITERAL1
+TASK_FOREVER	LITERAL1
+TASK_IMMEDIATE	LITERAL1
+TASK_ONCE	LITERAL1
+_TASK_TIMECRITICAL	LITERAL1
+_TASK_SLEEP_ON_IDLE_RUN	LITERAL1
+_TASK_STATUS_REQUEST	LITERAL1
+_TASK_WDT_IDS	LITERAL1
+_TASK_LTS_POINTER	LITERAL1
+_TASK_ROLLOVER_FIX	LITERAL1
 #######################################
 

+ 1 - 1
library.properties

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

+ 129 - 84
src/TaskScheduler.h

@@ -50,6 +50,13 @@
 //    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.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
 
 
 /* ============================================
@@ -92,6 +99,7 @@ THE SOFTWARE.
  *	#define _TASK_STATUS_REQUEST    // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
  *	#define _TASK_WDT_IDS           // Compile with support for wdt control points and task ids
  *  #define _TASK_LTS_POINTER       // Compile with support for local task storage pointer
+ *  #define _TASK_ROLLOVER_FIX		// Compensate for millis() rollover once every 47 days
  */
 
 #ifdef _TASK_SLEEP_ON_IDLE_RUN
@@ -99,8 +107,18 @@ THE SOFTWARE.
 #include <avr/power.h>
 #endif
 
+#define TASK_IMMEDIATE			0
+#define TASK_SECOND			1000L
+#define TASK_MINUTE		   60000L
+#define TASK_HOUR		 3600000L
+#define TASK_FOREVER		 (-1)
+#define TASK_ONCE				1
 
 #ifdef _TASK_STATUS_REQUEST
+
+#define	_TASK_SR_NODELAY 	1
+#define	_TASK_SR_DELAY		2
+
 class StatusRequest {
 	public:
 		StatusRequest() {iCount = 0; iStatus = 0; }
@@ -113,7 +131,7 @@ class StatusRequest {
 		
 	private:
 		unsigned int	iCount;  // waiting for more that 65000 events seems unreasonable: unsigned int should be sufficient
-		int			iStatus;  // negative = error;  zero = OK; >positive = OK with a specific status
+		int				iStatus;  // negative = error;  zero = OK; >positive = OK with a specific status
 };
 #endif
 
@@ -123,76 +141,78 @@ class Scheduler;
 class Task {
     friend class Scheduler;
     public:
-	Task(unsigned long aInterval=0, long aIterations=0, void (*aCallback)()=NULL, Scheduler* aScheduler=NULL, boolean aEnable=false, bool (*aOnEnable)()=NULL, void (*aOnDisable)()=NULL);
+		Task(unsigned long aInterval=0, long aIterations=0, void (*aCallback)()=NULL, Scheduler* aScheduler=NULL, boolean aEnable=false, bool (*aOnEnable)()=NULL, void (*aOnDisable)()=NULL);
 #ifdef _TASK_STATUS_REQUEST
-	Task(void (*aCallback)()=NULL, Scheduler* aScheduler=NULL, bool (*aOnEnable)()=NULL, void (*aOnDisable)()=NULL);
+		Task(void (*aCallback)()=NULL, Scheduler* aScheduler=NULL, bool (*aOnEnable)()=NULL, void (*aOnDisable)()=NULL);
 #endif
 
-	void enable();
-	bool enableIfNot();
-	void enableDelayed(unsigned long aDelay=0);
-	void delay(unsigned long aDelay=0);
-	void forceNextIteration(); 
-	void restart();
-	void restartDelayed(unsigned long aDelay=0);
-	bool disable();
-	inline bool isEnabled() { return iEnabled; }
-	void set(unsigned long aInterval, long aIterations, void (*aCallback)(),bool (*aOnEnable)()=NULL, void (*aOnDisable)()=NULL);
-	void setInterval(unsigned long aInterval);
-	inline unsigned long getInterval() { return iInterval; }
-	void setIterations(long aIterations);
-	inline long getIterations() { return iIterations; }
-	inline unsigned long getRunCounter() { return iRunCounter; }
-	inline void setCallback(void (*aCallback)()) { iCallback = aCallback; }
-	inline void setOnEnable(bool (*aCallback)()) { iOnEnable = aCallback; }
-	inline void setOnDisable(void (*aCallback)()) { iOnDisable = aCallback; }
+		void enable();
+		bool enableIfNot();
+		void enableDelayed(unsigned long aDelay=0);
+		void delay(unsigned long aDelay=0);
+		void forceNextIteration(); 
+		void restart();
+		void restartDelayed(unsigned long aDelay=0);
+		bool disable();
+		inline bool isEnabled() { return iEnabled; }
+		void set(unsigned long aInterval, long aIterations, void (*aCallback)(),bool (*aOnEnable)()=NULL, void (*aOnDisable)()=NULL);
+		void setInterval(unsigned long aInterval);
+		inline unsigned long getInterval() { return iInterval; }
+		void setIterations(long aIterations);
+		inline long getIterations() { return iIterations; }
+		inline unsigned long getRunCounter() { return iRunCounter; }
+		inline void setCallback(void (*aCallback)()) { iCallback = aCallback; }
+		inline void setOnEnable(bool (*aCallback)()) { iOnEnable = aCallback; }
+		inline void setOnDisable(void (*aCallback)()) { iOnDisable = aCallback; }
 #ifdef _TASK_TIMECRITICAL
-	inline long getOverrun() { return iOverrun; }
+		inline long getOverrun() { return iOverrun; }
 #endif
-	inline bool isFirstIteration() { return (iRunCounter <= 1); } 
-	inline bool isLastIteration() { return (iIterations == 0); }
+		inline bool isFirstIteration() { return (iRunCounter <= 1); } 
+		inline bool isLastIteration() { return (iIterations == 0); }
 #ifdef _TASK_STATUS_REQUEST
-	void waitFor(StatusRequest* aStatusRequest);
-	inline StatusRequest* getStatusRequest() {return iStatusRequest; }
+		void waitFor(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
+		void waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
+		inline StatusRequest* getStatusRequest() {return iStatusRequest; }
 #endif
 #ifdef _TASK_WDT_IDS
-	inline void setId(unsigned int aID) { iTaskID = aID; }
-	inline unsigned int getId() { return iTaskID; }
-	inline void setControlPoint(unsigned int aPoint) { iControlPoint = aPoint; }
-	inline unsigned int getControlPoint() { return iControlPoint; }
+		inline void setId(unsigned int aID) { iTaskID = aID; }
+		inline unsigned int getId() { return iTaskID; }
+		inline void setControlPoint(unsigned int aPoint) { iControlPoint = aPoint; }
+		inline unsigned int getControlPoint() { return iControlPoint; }
 #endif
 #ifdef _TASK_LTS_POINTER
-	inline void	setLtsPointer(void *aPtr) { iLTS = aPtr; }
-	inline void* getLtsPointer() { return iLTS; }
+		inline void	setLtsPointer(void *aPtr) { iLTS = aPtr; }
+		inline void* getLtsPointer() { return iLTS; }
 #endif
 	
     private:
-	void reset();
+		void reset();
 
-    volatile bool			iEnabled;
-	bool					iInOnEnable;
-    volatile unsigned long	iInterval;
-	volatile unsigned long	iPreviousMillis;
+		volatile bool			iEnabled;
+		volatile bool			iInOnEnable;
+		volatile unsigned long	iInterval;
+		volatile unsigned long	iPreviousMillis;
 #ifdef _TASK_TIMECRITICAL
-	volatile long			iOverrun; 
+		volatile long			iOverrun; 
 #endif
-	volatile long			iIterations;
-	long					iSetIterations; 
-	unsigned long			iRunCounter;
-	void					(*iCallback)();
-	bool					(*iOnEnable)();
-	void					(*iOnDisable)();
-	Task					*iPrev, *iNext;
-	Scheduler				*iScheduler;
+		volatile long			iIterations;
+		long					iSetIterations; 
+		unsigned long			iRunCounter;
+		void					(*iCallback)();
+		bool					(*iOnEnable)();
+		void					(*iOnDisable)();
+		Task					*iPrev, *iNext;
+		Scheduler				*iScheduler;
 #ifdef _TASK_STATUS_REQUEST
-	StatusRequest			*iStatusRequest;
+		StatusRequest			*iStatusRequest;
+		byte					iWaiting;
 #endif
 #ifdef _TASK_WDT_IDS
-	unsigned int			iTaskID;
-	unsigned int			iControlPoint;
+		unsigned int			iTaskID;
+		unsigned int			iControlPoint;
 #endif
 #ifdef _TASK_LTS_POINTER
-	void					*iLTS;
+		void					*iLTS;
 #endif
 };
 
@@ -213,6 +233,9 @@ class Scheduler {
 #ifdef _TASK_LTS_POINTER
 		inline void* currentLts() {return iCurrent->iLTS; }
 #endif
+#ifdef _TASK_TIMECRITICAL
+		inline bool isOverrun() { return (iCurrent->iOverrun < 0); }
+#endif
 
 	private:
 		Task	*iFirst, *iLast, *iCurrent;
@@ -282,14 +305,23 @@ void StatusRequest::signalComplete(int aStatus) {
  *  @param: aStatusRequest - a pointer for the StatusRequest to wait for.
  *  If aStatusRequest is NULL, request for waiting is ignored, and the waiting task is not enabled. 
  */
-void Task::waitFor(StatusRequest* aStatusRequest) {
+void Task::waitFor(StatusRequest* aStatusRequest, unsigned long aInterval, long aIterations) {
 	if ( ( iStatusRequest = aStatusRequest) ) { // assign internal StatusRequest var and check if it is not NULL
-		setIterations(1);
-		setInterval(0); 
+		setIterations(aIterations);
+		setInterval(aInterval); 
+		iWaiting = _TASK_SR_NODELAY;  // no delay
 		enable();
 	}
 }
 
+void Task::waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval, long aIterations) {
+	if ( ( iStatusRequest = aStatusRequest) ) { // assign internal StatusRequest var and check if it is not NULL
+		setIterations(aIterations);
+		if ( aInterval ) setInterval(aInterval);  // For the dealyed version only set the interval if it was not a zero
+		iWaiting = _TASK_SR_DELAY;  // with delay equal to the current interval
+		enable();
+	}
+}
 #endif
 
 /** Resets (initializes) the task/
@@ -312,6 +344,9 @@ void Task::reset() {
 #ifdef _TASK_LTS_POINTER
 	iLTS = NULL;
 #endif
+#ifdef _TASK_STATUS_REQUEST
+	iWaiting = 0;
+#endif
 }
 
 /** Explicitly set Task execution parameters
@@ -533,6 +568,7 @@ void Scheduler::execute() {
 #ifdef _TASK_SLEEP_ON_IDLE_RUN
 	bool		idleRun = true;
 #endif
+	unsigned long targetMillis;
 	
 	iCurrent = iFirst;
 
@@ -540,50 +576,59 @@ void Scheduler::execute() {
 		do {   		
 			if (iCurrent->iEnabled) {
 	#ifdef _TASK_WDT_IDS
-	// For each task the control points are initialized to avoid confusion because of carry-over
+	// For each task the control points are initialized to avoid confusion because of carry-over:
 				iCurrent->iControlPoint = 0;
 	#endif
+	
+	// Disable task on last iteration:
 				if (iCurrent->iIterations == 0) {
 					iCurrent->disable();
 					break;
 				}
 	#ifdef  _TASK_STATUS_REQUEST
-	// If StatusRequest object was provided (not NULL) and it is still bending, this task should not run
-	// Otherwise, continue with execution as usual.  Tasks waiting to StatusRequest usually have  interval = 0, and iterations = 1
-	// so they will run once immediately. 
-				if ( iCurrent->iStatusRequest && (iCurrent->iStatusRequest)->pending() ) break;
+	// 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->iWaiting = 0;
+				}
 	#endif
-				if ( iCurrent->iInterval > 0 ) {
-					unsigned long targetMillis = iCurrent->iPreviousMillis + iCurrent->iInterval;
-					if ( targetMillis <= millis() ) {
-						if ( iCurrent->iIterations > 0 ) iCurrent->iIterations--;  // do not decrement (-1) being a signal of eternal task
-						iCurrent->iRunCounter++;
-						iCurrent->iPreviousMillis += iCurrent->iInterval;
-
+	// Determine when current task is supposed to run
+	// Once every 47 days there is a rollover execution which will occur due to millis and targetMillis rollovers
+	// That is why there is an option to compile with rollover fix
+	// Example
+	//	iPreviousMillis = 65000
+	//	iInterval = 600
+	//	millis() = 65500
+	//  targetMillis = 65000 + 600 = (should be 65600) 65 (due to rollover)
+	//	so 65 < 65500. should be 65600 > 65500. - task will be scheduled incorrectly
+	//  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;
+	#ifdef _TASK_ROLLOVER_FIX
+				if ( targetMillis < iCurrent->iPreviousMillis ) {  // targetMillis rolled over!
+					if ( iCurrent->iPreviousMillis > ( millis() - iCurrent->iInterval) )  break;
+				}
+				else
+	#endif
+					if ( targetMillis > millis() ) break;
+	
+				iCurrent->iPreviousMillis = targetMillis;
 	#ifdef _TASK_TIMECRITICAL
-	// Updated_previous+current should put us into the future, so iOverrun should be positive or zero. 
+	// 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) (iCurrent->iPreviousMillis + iCurrent->iInterval - millis());
 	#endif
-
-						if ( iCurrent->iCallback ) {
-							( *(iCurrent->iCallback) )();
-	#ifdef _TASK_SLEEP_ON_IDLE_RUN
-							idleRun = false;
-	#endif
-						}
-						break;
-					}
-				}
-				else {
-					if ( iCurrent->iIterations > 0 ) iCurrent->iIterations--;  // do not decrement (-1) being a signal of eternal task
-					iCurrent->iRunCounter++;
-					if ( iCurrent->iCallback ) {
-						( *(iCurrent->iCallback) )();
+				if ( iCurrent->iIterations > 0 ) iCurrent->iIterations--;  // do not decrement (-1) being a signal of never-ending task
+				iCurrent->iRunCounter++;
+				if ( iCurrent->iCallback ) {
+					( *(iCurrent->iCallback) )();
 	#ifdef _TASK_SLEEP_ON_IDLE_RUN
-						idleRun = false;
+					idleRun = false;
 	#endif
-					}
 				}
 			}
 		} while (0); //guaranteed single run - allows use of "break" to exit