Przeglądaj źródła

Version 2.0.0 support for layered task prioritization

 * _TASK_PRIORITY - support for layered task prioritization
Anatoli Arkhipenko 10 lat temu
rodzic
commit
965f1b768d

+ 8 - 4
README

@@ -1,5 +1,5 @@
 Task Scheduler – cooperative multitasking for Arduino microcontrollers
-Version 1.9.2: 2015-12-20
+Version 2.0.0: 2015-12-23
   
 OVERVIEW:
  A lightweight implementation of cooperative multitasking (task scheduling) supporting:
@@ -8,13 +8,17 @@ OVERVIEW:
  3. Execution of tasks in predefined sequence
  4. Dynamic change of task execution parameters (frequency, number of iterations, callback function)
  5. Power saving via entering IDLE sleep mode between tasks are scheduled to run
- 6. Support for task invocation via Status Request object
- 7. Support for task IDs and Control Points for error handling and watchdog timer
- 8. Support for Local Task Storage pointer (allowing use of same callback code for multiple tasks)
+ 6. Task invocation via Status Request object
+ 7. Task IDs and Control Points for error handling and watchdog timer
+ 8. Local Task Storage pointer (allowing use of same callback code for multiple tasks)
+ 9. Layered task prioritization
 
 Scheduling overhead: between 15 and 18 microseconds per scheduling pass (check the banchmark example).
 
 Changelog:
+v2.0.0:
+    2015-12-22 - _TASK_PRIORITY - support for layered task prioritization
+
 v1.9.2:
     2015-11-28 - _TASK_ROLLOVER_FIX is deprecated (not necessary)
     2015-12-16 - bug fixes: automatic millis rollover support for delay methods

+ 0 - 0
examples/Scheduler_example1/Scheduler_example1.ino → examples/Scheduler_example01/Scheduler_example01.ino


+ 0 - 0
examples/Scheduler_example2/Scheduler_example2.ino → examples/Scheduler_example02/Scheduler_example02.ino


+ 0 - 0
examples/Scheduler_example3/Scheduler_example3.ino → examples/Scheduler_example03/Scheduler_example03.ino


+ 0 - 0
examples/Scheduler_example4_StatusRequest/Scheduler_example4_StatusRequest.ino → examples/Scheduler_example04_StatusRequest/Scheduler_example04_StatusRequest.ino


+ 0 - 0
examples/Scheduler_example5_StatusRequest/Scheduler_example5_StatusRequest.ino → examples/Scheduler_example05_StatusRequest/Scheduler_example05_StatusRequest.ino


+ 0 - 0
examples/Scheduler_example6_IDLE/Scheduler_example6_IDLE.ino → examples/Scheduler_example06_IDLE/Scheduler_example06_IDLE.ino


+ 0 - 0
examples/Scheduler_example7_WDT/Scheduler_example7_WDT.ino → examples/Scheduler_example07_WDT/Scheduler_example07_WDT.ino


+ 0 - 0
examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino → examples/Scheduler_example08_LTS/Scheduler_example08_LTS.ino


+ 0 - 0
examples/Scheduler_example9_TimeCritical/Scheduler_example9_TimeCritical.ino → examples/Scheduler_example09_TimeCritical/Scheduler_example09_TimeCritical.ino


+ 105 - 0
examples/Scheduler_example11_Priority/Scheduler_example11_Priority.ino

@@ -0,0 +1,105 @@
+/**
+ * This is a test of TaskScheduler layered priority funtionality
+ * 
+ * Current test employs two priority layers:
+ * Base scheduler runs tasks t1, t2 and t3
+ * High priority scheduler runs tasks t4 and t5
+ * 
+ * Sequence of task scheduling (not execution!) is:
+ * 4, 5, 1, 4, 5, 2, 4, 5, 3 = one base scheduler pass
+ * 
+ * Scheduling overhead (at 20 micros per one pass) is: (B + B * H) * T = (3 + 3 * 2) * 18 = 162 micros
+ * where
+ *  B - number of tasks in the base scheduler's chain
+ *  H - number of tasks in the high priority scheduler's chain
+ *  T - scheduling overhead for 1 pass (~15-18 microseconds) 
+ *  
+ *  Actual task execution order:
+
+Scheduler Priority Test
+Task: 40:  0 Start delay = 0
+Task: 50: 10  Start delay = 10
+Task: 1:  21  Start delay = 21
+Task: 2:  31  Start delay = 31
+Task: 3:  41  Start delay = 41
+
+Task: 40: 500 Start delay = 0
+Task: 40: 1000  Start delay = 0
+Task: 50: 1010  Start delay = 10
+Task: 1:  1021  Start delay = 20
+Task: 40: 1500  Start delay = 0
+Task: 40: 2000  Start delay = 0
+Task: 50: 2011  Start delay = 11
+Task: 1:  2022  Start delay = 21
+Task: 2:  2032  Start delay = 32
+Task: 40: 2500  Start delay = 0
+Task: 40: 3000  Start delay = 0
+Task: 50: 3010  Start delay = 10
+Task: 1:  3021  Start delay = 20
+Task: 3:  3032  Start delay = 32
+
+Task: 40: 3500  Start delay = 0
+Task: 40: 4000  Start delay = 0
+Task: 50: 4011  Start delay = 11
+Task: 1:  4022  Start delay = 21
+Task: 2:  4032  Start delay = 32
+Task: 40: 4500  Start delay = 0
+Task: 40: 5000  Start delay = 0
+Task: 50: 5010  Start delay = 10
+Task: 1:  5021  Start delay = 20
+Task: 40: 5500  Start delay = 0
+Task: 40: 6000  Start delay = 0
+Task: 50: 6010  Start delay = 10
+Task: 1:  6022  Start delay = 21
+Task: 2:  6032  Start delay = 32
+Task: 3:  6043  Start delay = 42
+
+ */
+ 
+#define _TASK_SLEEP_ON_IDLE_RUN
+#define _TASK_PRIORITY
+#define _TASK_WDT_IDS
+#define _TASK_TIMECRITICAL
+#include <TaskScheduler.h>
+
+Scheduler r, hpr;
+
+// Callback methods prototypes
+void tCallback();
+
+// Tasks
+Task t1(1000, TASK_FOREVER, &tCallback, &r);  //adding task to the chain on creation
+Task t2(2000, TASK_FOREVER, &tCallback, &r);
+Task t3(3000, TASK_FOREVER, &tCallback, &r);
+
+Task t4(500, TASK_FOREVER, &tCallback, &hpr);  //adding task to the chain on creation
+Task t5(1000, TASK_FOREVER, &tCallback, &hpr);  //adding task to the chain on creation
+
+void tCallback() {
+  Scheduler &s = Scheduler::currentScheduler();
+  Task &t = s.currentTask();
+  
+  Serial.print("Task: "); Serial.print(t.getId());Serial.print(":\t");
+  Serial.print(millis()); Serial.print("\tStart delay = "); Serial.println(t.getStartDelay());
+  delay(10);
+
+  if (t.getId() == 3) Serial.println();
+}
+
+void setup () {
+  Serial.begin(115200);
+  Serial.println("Scheduler Priority Test");
+
+  t4.setId(40);
+  t5.setId(50);
+
+  r.setHighPriorityScheduler(&hpr); 
+  r.enableAll(true); // this will recursively enable the higher priority tasks as well
+}
+
+
+void loop () {
+  
+  r.execute();
+  
+}

+ 136 - 0
examples/Scheduler_example12_Priority/Scheduler_example12_Priority.ino

@@ -0,0 +1,136 @@
+/**
+ * This is a test of TaskScheduler layered priority funtionality
+ * 
+ * Current test employs three priority layers:
+ * Base scheduler runs tasks t1, t2 and t3
+ * High priority scheduler runs tasks t4 and t5
+ * Highest priority scheduler runs tasks t6 and t7
+ * 
+ * Sequence of task scheduling (not execution!) is:
+ * 6, 7, 4, 6, 7, 5, 1, 6, 7, 4, 6, 7, 5, 2, 6, 7, 4, 6, 7, 5, 3 = one base scheduler pass
+ * 
+ * Scheduling overhead (at 20 micros per one pass) is: (B + B * H + B * H * C) * T = (3 + 3 * 2 + 3 * 2 * 2) * 18 = 378 micros
+ * where
+ *  B - number of tasks in the base scheduler's chain
+ *  H - number of tasks in the high priority scheduler's chain
+ *  C - number of tasks in the critical priority scheduler's chain
+ *  T - scheduling overhead for 1 pass (~15-18 microseconds) 
+ *  
+ *  Actual task execution order:
+
+Scheduler Priority Test
+Task: 600:  0 Start delay = 0
+Task: 700:  10  Start delay = 10
+Task: 40: 21  Start delay = 21
+Task: 50: 31  Start delay = 31
+Task: 1:  43  Start delay = 41
+Task: 2:  53  Start delay = 53
+Task: 3:  63  Start delay = 63
+
+Task: 600:  500 Start delay = 0
+Task: 40: 510 Start delay = 10
+Task: 600:  1000  Start delay = 0
+Task: 700:  1010  Start delay = 10
+Task: 40: 1021  Start delay = 21
+Task: 50: 1032  Start delay = 32
+Task: 1:  1043  Start delay = 43
+Task: 600:  1500  Start delay = 0
+Task: 40: 1510  Start delay = 10
+Task: 600:  2000  Start delay = 0
+Task: 700:  2011  Start delay = 11
+Task: 40: 2022  Start delay = 22
+Task: 50: 2032  Start delay = 32
+Task: 1:  2043  Start delay = 43
+Task: 2:  2054  Start delay = 54
+Task: 600:  2500  Start delay = 0
+Task: 40: 2510  Start delay = 10
+Task: 600:  3000  Start delay = 0
+Task: 700:  3010  Start delay = 10
+Task: 40: 3021  Start delay = 21
+Task: 50: 3032  Start delay = 32
+Task: 1:  3043  Start delay = 43
+Task: 3:  3053  Start delay = 53
+
+Task: 600:  3500  Start delay = 0
+Task: 40: 3510  Start delay = 10
+Task: 600:  4000  Start delay = 0
+Task: 700:  4011  Start delay = 11
+Task: 40: 4022  Start delay = 22
+Task: 50: 4032  Start delay = 32
+Task: 1:  4043  Start delay = 43
+Task: 2:  4054  Start delay = 54
+Task: 600:  4500  Start delay = 0
+Task: 40: 4510  Start delay = 10
+Task: 600:  5000  Start delay = 0
+Task: 700:  5010  Start delay = 10
+Task: 40: 5021  Start delay = 21
+Task: 50: 5031  Start delay = 31
+Task: 1:  5043  Start delay = 43
+Task: 600:  5500  Start delay = 0
+Task: 40: 5511  Start delay = 11
+Task: 600:  6000  Start delay = 0
+Task: 700:  6010  Start delay = 10
+Task: 40: 6022  Start delay = 22
+Task: 50: 6032  Start delay = 32
+Task: 1:  6043  Start delay = 43
+Task: 2:  6053  Start delay = 53
+Task: 3:  6065  Start delay = 65
+
+ */
+ 
+#define _TASK_SLEEP_ON_IDLE_RUN
+#define _TASK_PRIORITY
+#define _TASK_WDT_IDS
+#define _TASK_TIMECRITICAL
+#include <TaskScheduler.h>
+
+Scheduler r;
+Scheduler hpr;
+Scheduler cpr;
+
+// Callback methods prototypes
+void tCallback();
+
+// Tasks
+Task t1(1000, TASK_FOREVER, &tCallback, &r);  //adding task to the chain on creation
+Task t2(2000, TASK_FOREVER, &tCallback, &r);
+Task t3(3000, TASK_FOREVER, &tCallback, &r);
+
+Task t4(500, TASK_FOREVER, &tCallback, &hpr);  //adding task to the chain on creation
+Task t5(1000, TASK_FOREVER, &tCallback, &hpr);  //adding task to the chain on creation
+
+Task t6(500, TASK_FOREVER, &tCallback, &cpr);  //adding task to the chain on creation
+Task t7(1000, TASK_FOREVER, &tCallback, &cpr);  //adding task to the chain on creation
+
+void tCallback() {
+  Scheduler &s = Scheduler::currentScheduler();
+  Task &t = s.currentTask();
+  
+  Serial.print("Task: "); Serial.print(t.getId());Serial.print(":\t");
+  Serial.print(millis()); Serial.print("\tStart delay = "); Serial.println(t.getStartDelay());
+  delay(10);
+
+  if (t.getId() == 3) Serial.println();
+}
+
+void setup () {
+  Serial.begin(115200);
+  Serial.println("Scheduler Priority Test");
+
+  t4.setId(40);
+  t5.setId(50);
+  
+  t6.setId(600);
+  t7.setId(700);
+
+  r.setHighPriorityScheduler(&hpr); 
+  hpr.setHighPriorityScheduler(&cpr); 
+  r.enableAll(true); // this will recursively enable the higher priority tasks as well
+}
+
+
+void loop () {
+  
+  r.execute();
+  
+}

BIN
extras/TaskScheduler.doc


+ 455 - 144
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="20151128;23410000">
+	<META NAME="CHANGED" CONTENT="20151223;16480000">
 	<META NAME="Info 1" CONTENT="">
 	<META NAME="Info 2" CONTENT="">
 	<META NAME="Info 3" CONTENT="">
@@ -15,7 +15,7 @@
 	<!--
 		@page { margin: 0.79in }
 		P { margin-bottom: 0.08in; direction: ltr; color: #000000; widows: 0; orphans: 0 }
-		P.western { font-family: "Liberation Serif", "Times New Roman", serif; font-size: 12pt; so-language: en-US }
+		P.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; so-language: zh-CN }
 		P.ctl { font-family: "Lohit Hindi", "MS Mincho"; font-size: 12pt; so-language: hi-IN }
 		A:link { color: #0000ff }
@@ -25,10 +25,10 @@
 <BODY LANG="en-US" TEXT="#000000" LINK="#0000ff" BGCOLOR="#ffffff" DIR="LTR">
 <P CLASS="western" STYLE="margin-bottom: 0in"><FONT SIZE=4 STYLE="font-size: 15pt"><B>Task
 Scheduler</B></FONT></P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>cooperative
+<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.9.2: 2015-12-20</B></FONT></P>
+<FONT SIZE=2 STYLE="font-size: 11pt"><B>Version 2.0.0: 2015-12-23</B></FONT></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>OVERVIEW</B>:</P>
@@ -55,6 +55,8 @@ supporting:</P>
 	<LI><P CLASS="western" STYLE="margin-bottom: 0in">Support for Local
 	Task Storage pointer (allowing use of same callback code for
 	multiple tasks)</P>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in">Support for
+	layered task prioritization</P>
 </OL>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
@@ -92,6 +94,13 @@ processed by the <B>Scheduler</B> in the order they were added
 (linked together).</P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Starting with
+version 2.0.0 TaskScheduler supports task prioritization. Please
+refer to the specific chapter of this manual for details on layered
+prioritization. </B>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
 <P CLASS="western" STYLE="margin-bottom: 0in">Each task performs its
 function via a callback method. Scheduler calls Task’s callback
 method periodically until task is disabled or runs out of iterations.
@@ -126,14 +135,14 @@ 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=570 BORDER=0></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><IMG SRC="TaskScheduler_html.png" NAME="graphics1" ALIGN=BOTTOM WIDTH=664 HEIGHT=517 BORDER=0></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>TaskScheduler</B>
 library maybe compiled with different compilation controls
 enabled/disabled. This is a way to limit TaskScheduler functionality
 (and size) for specific purpose (sketch). This is achieved by
-defining specific #<B>define</B> paramenters <I>before</I>
+defining specific #<B>define</B> parameters <I>before</I>
 TaskScheduler.h header file. Specifically:</P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
@@ -150,7 +159,7 @@ tasks in the chain always requires immediate execution (aInterval =
 execution.</P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Task
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>NOTE: </B>Task
 Scheduler uses <B>millis()</B> to determine if tasks are ready to be
 invoked. Therefore, if you put your device to any “deep” sleep
 mode disabling timer interrupts, the <B>millis()</B> count will be
@@ -209,10 +218,10 @@ scheduled, and where next execution time of the task falls. Two
 methods provide this information. 
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>Task::getStartDelay()
-</B><SPAN STYLE="font-weight: normal">method: return number of
-milliseconds between current system time (millis) and point in time
-when the task was scheduled to start. A value of 0 (zero) indicates
-that task started right on time per schedule. </SPAN>
+</B>method: return number of milliseconds between current system time
+(millis) and point in time when the task was scheduled to start. A
+value of 0 (zero) indicates that task started right on time per
+schedule. 
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><B>Task::getOverrun()</B>
 method: If <B>getOverrun </B>returns a negative value, this Task’s
@@ -260,9 +269,9 @@ anything hardware dependent) can be blocked (or hung), by failed
 hardware. In this case, a watchdog timer could be employed to trap
 such a failed task, and identify which one (by task id) and where in
 the task (by a control point) the problem is likely located.</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"> 
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>by
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>NOTE: </B>by
 default, talk IDs are assigned sequentially (1, 2, 3, …) to the
 tasks as they are being created. Programmer can assign a specific
 task id. <B>Task ids are unsigned integers.</B></P>
@@ -295,6 +304,17 @@ enabled by placing appropriate #define statements in front of the
 #include statement for the TaskScheduler header file.</P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
+<P CLASS="western" STYLE="margin-bottom: 0in">#define <B>_TASK_PRIORITY</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in">…will compile
+TaskScheduler with support for layered task prioritization. Task
+prioritization is achieved by creating several schedulers, and
+organizing them in priority layers. Tasks are assigned to schedulers
+corresponding to their priority. Tasks assigned to the “higher”
+layers are evaluated for invocation more frequently, and are given
+priority in execution in case of the scheduling coincidence. More
+about layered prioritization in the API documentation and
+TaskScheduler examples.  
+</P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
@@ -303,28 +323,163 @@ enabled by placing appropriate #define statements in front of the
 </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 CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">Starting with version
+2.0.0 TaskScheduler supports task prioritization. Priority is
+associated with a <B>Scheduler</B>, not individual <B>Tasks</B>,
+hence the concept of priority layers. Tasks subsequently are assigned
+to schedulers corresponding to their desired priority. The lowest
+priority Scheduler is called “<B>base scheduler</B>” or “<B>base
+layer</B>”. Let’s call higher priority schedulers by their
+priority number, with larger number corresponding to higher priority
+of task execution. 
 </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">Task prioritization is
+achieved by executing the entire chain of tasks of the higher
+priority scheduler for every single step (task) of the lower priority
+chain. <B>Note</B> that actual callback method invocation depends on
+priority <B>and </B>the timing of task schedule. However, higher
+priority tasks are evaluated more frequently and are given priority
+in case of scheduling collision. 
+</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">For most tasks
+TaskScheduler <B>does not need </B>task priority functionality.
+Prioritization requires additional scheduling overhead, and should be
+used only for critical tasks.</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, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">execute()
-</FONT></FONT>loop significantly.</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">A few points on that:</P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
+<P CLASS="western" STYLE="margin-bottom: 0in">1. Plain (non-layered)
+execution chain is simple and efficient. The main idea is to minimize
+scheduling overhead by Scheduler going through the chain. Each
+priority layer adds scheduling overhead to overall task chain
+execution. Let’s review 3 scenarios:</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>I.
+Flat chain of 7 tasks:</B></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Scheduling
+evaluation sequence:</P>
+<P CLASS="western" ALIGN=CENTER STYLE="margin-left: 0.49in; margin-bottom: 0in">
+1 <FONT FACE="Wingdings"></FONT> 2 <FONT FACE="Wingdings"></FONT>
+3 <FONT FACE="Wingdings"></FONT> 4 <FONT FACE="Wingdings"></FONT>
+5 <FONT FACE="Wingdings"></FONT> 6 <FONT FACE="Wingdings"></FONT>
+7</P>
+<P CLASS="western" ALIGN=CENTER STYLE="margin-left: 0.49in; margin-bottom: 0in">
+<BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Scheduling
+overhead:</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">O
+= B * T = 7 * 18 = 126 microseconds,</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Where:</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">O
+– scheduling overhead</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">B
+– number of tasks in the base layer</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">T
+– scheduling overhead of a single task execution evaluation
+(currently with Arduino Uno running at 16 Mhz is between 15 and 18
+microseconds).</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>II.
+Two priority layers of 7 tasks. </B>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>	</B>Tasks
+1, 2, 3, 4, 5 are base priority and 6, 7 are higher priority:</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">Scheduling
+evaluation sequence:</P>
+<P CLASS="western" ALIGN=CENTER STYLE="margin-left: 0.49in; margin-bottom: 0in">
+6 <FONT FACE="Wingdings"></FONT> 7 <FONT FACE="Wingdings"></FONT>
+1 <FONT FACE="Wingdings"></FONT> 6 <FONT FACE="Wingdings"></FONT>
+7 <FONT FACE="Wingdings"></FONT> 2 <FONT FACE="Wingdings"></FONT>
+6 <FONT FACE="Wingdings"></FONT> 7 <FONT FACE="Wingdings"></FONT>
+3 <FONT FACE="Wingdings"></FONT> 6 <FONT FACE="Wingdings"></FONT>
+7 <FONT FACE="Wingdings"></FONT> 4 <FONT FACE="Wingdings"></FONT>
+6 <FONT FACE="Wingdings"></FONT> 7 <FONT FACE="Wingdings"></FONT>
+5</P>
+<P CLASS="western" ALIGN=CENTER STYLE="margin-left: 0.49in; margin-bottom: 0in">
+<BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Scheduling
+overhead:</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">O
+= (B + B * P1) * T = (5 + 5 * 2) * 18 = 270 microseconds,</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Where:</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">O
+– scheduling overhead</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">B
+– number of tasks in the base layer</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">P1
+– number of tasks in the priority 1 layer</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">T
+– scheduling overhead of a single task execution evaluation
+(currently with Arduino Uno running at 16 Mhz is between 15 and 18
+microseconds).</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>III.
+Three priority layers of 7 tasks. </B>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>	</B>Tasks
+1, 2, 3, are base priority, 4, 5 are priority 1, and 6, 7 are
+priority 2:</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">Scheduling
+evaluation sequence:</P>
+<P CLASS="western" ALIGN=CENTER STYLE="margin-left: 0.49in; margin-bottom: 0in">
+6 <FONT FACE="Wingdings"></FONT> 7 <FONT FACE="Wingdings"></FONT>
+4 <FONT FACE="Wingdings"></FONT> 6 <FONT FACE="Wingdings"></FONT>
+7 <FONT FACE="Wingdings"></FONT> 5 <FONT FACE="Wingdings"></FONT>
+1 <FONT FACE="Wingdings"></FONT> 6 <FONT FACE="Wingdings"></FONT>
+7 <FONT FACE="Wingdings"></FONT> 4 <FONT FACE="Wingdings"></FONT>
+6 <FONT FACE="Wingdings"></FONT> 7 <FONT FACE="Wingdings"></FONT>
+5 <FONT FACE="Wingdings"></FONT> 2 <FONT FACE="Wingdings"></FONT>6
+<FONT FACE="Wingdings"></FONT> 7 <FONT FACE="Wingdings"></FONT>
+4 <FONT FACE="Wingdings"></FONT> 6 <FONT FACE="Wingdings"></FONT>
+7 <FONT FACE="Wingdings"></FONT> 5 <FONT FACE="Wingdings"></FONT>
+3 
+</P>
+<P CLASS="western" ALIGN=CENTER STYLE="margin-left: 0.49in; margin-bottom: 0in">
+<BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Scheduling
+overhead:</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">O
+= (B + B * P1 + B * P1 * P2) * T = (3 + 3 * 2 + 3 * 2 * 2) * 18 = 378
+microseconds,</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Where:</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">O
+– scheduling overhead</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">B
+– number of tasks in the base layer</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">P1
+– number of tasks in the priority 1 layer</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">P2
+– number of tasks in the priority 2 layer</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">T
+– scheduling overhead of a single task execution evaluation
+(currently with Arduino Uno running at 16 Mhz is between 15 and 18
+microseconds).</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">Scheduling overhead of
+a 3 layer prioritization approach is 3 times higher than that of a
+flat execution chain. <B>Do</B> evaluate if task prioritization is
+really required for your sketch.</P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
@@ -338,7 +493,7 @@ cooperative behavior.</P>
 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
+period of time, no one 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>
@@ -426,7 +581,7 @@ callback methods written for cooperative multitasking.</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, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">delay()</FONT></FONT><FONT FACE="Andale Mono, MS Mincho">
+<B>DO NOT</B> use Arduino's  <FONT FACE="FreeMono, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt"><B>delay</B></FONT></FONT><FONT FACE="FreeMono, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">()</FONT></FONT><FONT FACE="Andale Mono, MS Mincho">
 </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
@@ -533,7 +688,7 @@ 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">b)
-Same goes to <FONT FACE="FreeMono, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">pulseIn()</FONT></FONT>
+Same goes to <FONT FACE="FreeMono, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt"><B>pulseIn</B></FONT></FONT><FONT FACE="FreeMono, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">()</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>
@@ -711,7 +866,7 @@ stuff // one loop action</FONT></FONT></P>
 </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, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">setCallback()
+pass control from one to the other via <FONT FACE="FreeMono, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt"><B>setCallback</B></FONT></FONT><FONT FACE="FreeMono, MS Mincho, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">()
 </FONT></FONT>method:</P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
@@ -792,11 +947,11 @@ 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">This
-will execute all  parts of the callback function in three successive
-steps, sheduled immediately, but allowing other tasks in the chain to
-run. Notice that task is scheduled to run immediately, and 1 second
-period is achieved by delaying the task for 1000 millis at the last
-step. 
+will execute all parts of the callback function in three successive
+steps, scheduled immediately, but allowing other tasks in the chain
+to run. Notice 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>
@@ -1034,12 +1189,12 @@ getIterations() </B>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>long getOverrun()</B></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; font-weight: normal">
-If library is compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>long getStartDelay()</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, you can assess how much later the callback method was
 invoked against when it was scheduled to be invoked. The return value
-of  <B>getOverrun() </B>method provides this information in
+of  <B>getStartDelay () </B>method provides this information in
 milliseconds. 
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
@@ -1391,6 +1546,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-left: 0.49in; margin-bottom: 0in"><BR>
+</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">
@@ -1477,6 +1634,95 @@ implementation options.
 </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-bottom: 0in; page-break-after: avoid">
+<B>STATUS REQUEST:</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<B>CREATION:</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>StatusRequest()</B><BR><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Default
+constructor. 
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes
+no parameters. Creates Status Request object, which is assigned a
+status of “completed” on creation. 
+</P>
+<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 = 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
+wait on multiple events. For instance, <B>setWaiting(3)</B> will wait
+on three signals. An example could be waiting for completion of
+measurements from 3 sensors. 
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool signal(int
+aStatus)</B></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Signals
+completion of the event to the Status Request object, and passes a
+completion code, which could be interrogated later. 
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
+</B> passing a <B>negative</B> status code to the status request
+object is considered reporting an error condition, and will complete
+the status request regardless of how many outstanding signals it is
+still waiting for. 
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note</B>:
+only the latest status code is kept.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool signalComplete
+(int aStatus)</B></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Signals
+completion of <B>ALL</B> events to the Status Request object, and
+passes a completion code, which could be interrogated later. The
+status request completes regardless of how many events it is still
+waiting on. 
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool pending() </B>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
+<B>true</B> if status request is still waiting for event or events to
+happen.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool completed () </B>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
+<B>true</B> if status has completed.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>int getStatus()</B></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
+the status code passed to the status request object by the <B>signal()
+</B>and <B>signalComplete() </B>methods. 
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Any
+<B>positive</B> number is considered a successful completion status.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">A
+0 (zero) is considered a default successful completion status.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Any
+<B>negative</B> number is considered an error code and unsuccessful
+completion of a request.</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">
@@ -1571,8 +1817,10 @@ in case not tasks are scheduled to run.</P>
 <B>default</B> behavior of scheduler upon creation is to allow sleep
 mode. 
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void enableAll()</B></P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>void disableAll()</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void
+enableAll(bool aRecursive= true)</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>void disableAll(bool
+aRecursive= true)</B></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">enables
@@ -1580,6 +1828,11 @@ and disables (respectively) all tasks in the chain. Convenient if
 your need to enable/disable majority of the tasks (i.e. disable all
 and then enable one). 
 </P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
+support for layered task priority is enabled, supplying <B>aRecursive</B>
+parameter will enable/disable higher priority tasks as well (<B>true</B>,
+default), or tasks only on this priority layer (<B>false</B>). 
+</P>
 <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
 <BR><B>Task&amp; currentTask()<BR></B><BR>
 </P>
@@ -1606,21 +1859,34 @@ pointer to Local Task Storage of the task, currently executing via
 <B>execute()</B> loop <B>OR </B>for OnEnable and OnDisable methods,
 task being enabled or disabled. 
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void execute()</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>bool execute()</B></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Executes
-one scheduling pass, including end-of-pass sleep. This method is
-typically placed inside the <B>loop()</B> method of the sketch. Since
-<B>execute</B> exits after every pass, you can put additional
-statements after <B>execute</B> inside the <B>loop().</B></P>
+one scheduling pass, including (in case of the base priority
+scheduler) end-of-pass sleep. This method is typically placed inside
+the <B>loop()</B> method of the sketch. Since <B>execute</B> exits
+after every pass, you can put additional statements after <B>execute</B>
+inside the <B>loop().</B></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>If
+layered task prioritization is enabled, all higher priority tasks
+will be evaluated and invoked by the base <FONT FACE="Courier New, monospace">execute()</FONT>
+method. There is no need to call <FONT FACE="Courier New, monospace">execute()</FONT>
+of the higher priority schedulers explicitly. </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">Generally,
-execute will perform the following steps:</P>
+base priority execute will perform the following steps:</P>
 <OL>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in">Call higher
+	priority scheduler’s execute method, if provided.</P>
 	<LI><P CLASS="western" STYLE="margin-bottom: 0in">Ignore task
 	completely if it is disabled.</P>
 	<LI><P CLASS="western" STYLE="margin-bottom: 0in">Disable task if it
-	ran out of iterations (calling OnDesable, if necessary).</P>
+	ran out of iterations (calling OnDisable, if necessary).</P>
 	<LI><P CLASS="western" STYLE="margin-bottom: 0in">Check if task is
 	waiting on a StatusRequest object, and make appropriate scheduling
 	arrangements</P>
@@ -1650,100 +1916,54 @@ 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>
-</P>
-<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
-<B>STATUS REQUEST:</B></P>
 <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
 <BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
-<B>CREATION:</B></P>
+<B>TASK PRIORITY:</B></P>
 <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
 <BR>
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>StatusRequest()</B><BR><BR>
-</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Default
-constructor. 
-</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes
-no parameters. Creates Status Request object, which is assigned a
-status of “completed” on creation. 
-</P>
-<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 = 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
-wait on multiple events. For instance, <B>setWaiting(3)</B> will wait
-on three signals. An example could be waiting for completion of
-measurements from 3 sensors. 
-</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
-</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool signal(int
-aStatus)</B></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Signals
-completion of the event to the Status Request object, and passes a
-completion code, which could be interrogated later. 
-</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
-</B> passing a <B>negative</B> status code to the status request
-object is considered reporting an error condition, and will complete
-the status request regardless of how many outstanding signals it is
-still waiting for. 
-</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note</B>:
-only the latest status code is kept.</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
-</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool signalComplete
-(int aStatus)</B></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Signals
-completion of <B>ALL</B> events to the Status Request object, and
-passes a completion code, which could be interrogated later. The
-status request completes regardless of how many events it is still
-waiting on. 
+setHighPriorityScheduler(Scheduler* aScheduler);</B><BR><BR>
 </P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
-</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool pending() </B>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
+library is compiled with <FONT FACE="Courier New, monospace">_TASK_PRIORITY
+</FONT>enabled, this method associates current scheduler with a
+higher priority scheduler. 
 </P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
-<B>true</B> if status request is still waiting for event or events to
-happen.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE:
+</B>Only one <B>execute() </B>method needs to be explicitly called in
+the main <B>loop(). </B>That is the execute method of <B>base</B>
+priority scheduler. All higher priority schedulers are called by the
+base priority scheduler.</P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool completed () </B>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>static Scheduler&amp;
+currentScheduler()</B></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
+library is compiled with <FONT FACE="Courier New, monospace">_TASK_PRIORITY
+</FONT>enabled, this method returns reference to a scheduler, which
+invoked current task. 
 </P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
-<B>true</B> if status has completed.</P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>int getStatus()</B></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
-the status code passed to the status request object by the <B>signal()
-</B>and <B>signalComplete() </B>methods. 
-</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Any
-<B>positive</B> number is considered a successful completion status.</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">A
-0 (zero) is considered a default successful completion status.</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Any
-<B>negative</B> number is considered an error code and unsuccessful
-completion of a request.</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE:
+Please refer to examples 11 and 12 for illustration of Task Priority
+functionality</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"><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<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 CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
 <B>TASK_SECOND	(1000)</B></P>
@@ -1783,13 +2003,15 @@ interval for immediate execution</P>
 </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 CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <OL>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><B>EVENT DRIVEN
-	PROGRAMMING</B></P>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+	<B>EVENT DRIVEN PROGRAMMING</B></P>
 </OL>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in">Each of the processes
 of your application becomes a separate and distinct programming area,
@@ -1876,10 +2098,12 @@ measureHumidity();<BR>}<BR><BR><BR>void loop ()<BR>{<BR>
 taskManager.execute();<BR>}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT></FONT><BR>
 </P>
 <OL START=2>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in">“<FONT FACE="Times New Roman, serif"><B>NATIVE”
-	SUPPORT FOR FINITE STATE MACHINE</B></FONT></P>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+	“<FONT FACE="Times New Roman, serif"><B>NATIVE” SUPPORT FOR
+	FINITE STATE MACHINE</B></FONT></P>
 </OL>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Define
 “states” as callback method or methods. Each callback method
@@ -1942,10 +2166,12 @@ used to go through states.</FONT></P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <OL START=3>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>MULTIPLE
-	POSSIBLE CALLBACKS FOR TASK</B></FONT></P>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+	<FONT FACE="Times New Roman, serif"><B>MULTIPLE POSSIBLE CALLBACKS
+	FOR TASK</B></FONT></P>
 </OL>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">There
 may be a need to select an option for callback method based on
@@ -2024,11 +2250,13 @@ pass. </FONT>
 <P CLASS="western" STYLE="margin-bottom: 0in"><BR>
 </P>
 <OL START=3>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>INTERRUP-DRIVEN
-	EXECUTION SUPPORT </B></FONT>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+	<FONT FACE="Times New Roman, serif"><B>INTERRUP-DRIVEN EXECUTION
+	SUPPORT </B></FONT>
 	</P>
 </OL>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">In
 case of interrupt-driven program flow, tasks could be scheduled to
@@ -2112,11 +2340,13 @@ LOW;<BR>  <BR>}<BR><BR>void loop() {<BR>  // put your main code here,
 to run repeatedly:<BR>  r.execute();<BR>}<BR></FONT></FONT><BR>
 </P>
 <OL START=3>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>USING
-	ONENABLE AND ONDISBALE METHODS </B></FONT>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+	<FONT FACE="Times New Roman, serif"><B>USING ONENABLE AND ONDISBALE
+	METHODS </B></FONT>
 	</P>
 </OL>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Consider
 a task to flash onboard LED for 5 seconds with random frequency. Task
@@ -2301,11 +2531,13 @@ code here, to run repeatedly:</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
 <OL START=3>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>USING
-	STATUS REQUEST OBJECTS  </B></FONT>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+	<FONT FACE="Times New Roman, serif"><B>USING STATUS REQUEST OBJECTS 
+	</B></FONT>
 	</P>
 </OL>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">This
 test emulates querying 3 sensors once every 10 seconds, each could
@@ -2683,11 +2915,13 @@ loop() {</FONT></FONT></P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
 <OL START=3>
-	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>USING
-	LOCAL TASK STORAGE POINTER  </B></FONT>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+	<FONT FACE="Times New Roman, serif"><B>USING LOCAL TASK STORAGE
+	POINTER  </B></FONT>
 	</P>
 </OL>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<BR>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">Tasks
 can store a pointer to specific variable, structure or array, which
@@ -2797,6 +3031,83 @@ V1 = *((sensor_data*) ts.currentLts());</FONT></FONT></P>
 </P>
 <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
 </P>
+<OL START=3>
+	<LI><P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+	<FONT FACE="Times New Roman, serif"><B>ENABLING TASK PRIORITIZATION 
+	</B></FONT>
+	</P>
+</OL>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in; page-break-after: avoid">
+<BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">In
+certain cases you want a task to be invoked before others in case of
+scheduling collision (tasks ready to be invoked at the same time). In
+a flat execution chain scenario tasks are evaluated for execution in
+the order they were added to the chain. Therefore a single task has
+to wait for the rest of the chain to be evaluated to get a chance
+again. </FONT></FONT>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">Consider
+a scenario where a task taking gyroscope measurements has to be
+invoked as close to the actual scheduling time as possible. That is
+when task prioritization comes to help.  </FONT></FONT>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">Let’s
+say tasks t4 and t5 are taking measurements from gyroscope and
+accelerometer, and tasks t1, t2 and t3 are doing something less
+important.</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">This
+is how such setup is coded:</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>#define
+_TASK_PRIORITY</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>#include
+&lt;TaskScheduler.h&gt;</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Scheduler
+r, hpr;</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
+Tasks</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
+t1(1000, TASK_FOREVER, &amp;tCallback, &amp;r);  //base priority</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
+t2(2000, TASK_FOREVER, &amp;tCallback, &amp;r);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
+t3(3000, TASK_FOREVER, &amp;tCallback, &amp;r);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
+t4(10, TASK_FOREVER, &amp;tCallback, &amp;hpr);  // higher priority</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
+t5(100, TASK_FOREVER, &amp;tCallback, &amp;hpr);  //higher priority</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">…</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
+setup () {</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">  
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"> 
+…</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"> 
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>r.setHighPriorityScheduler(&amp;hpr);
+</FONT></FONT>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"> 
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>r.enableAll(true);
+// this will recursively enable the higher priority tasks as well</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
 <OL START=3>
 	<LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>FUTHER
 	INFROMATION</B></FONT></P>
@@ -2818,7 +3129,7 @@ time examples of TaskScheduler are available here:</FONT></FONT></P>
 <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>31</SDFIELD></P>
+	<P STYLE="margin-top: 0.35in; margin-bottom: 0in">	<SDFIELD TYPE=PAGE SUBTYPE=RANDOM FORMAT=ARABIC>33</SDFIELD></P>
 </DIV>
 </BODY>
-</HTML>
+</HTML>

+ 3 - 1
keywords.txt

@@ -62,7 +62,8 @@ getControlPoint	KEYWORD2
 setLtsPointer	KEYWORD2
 getLtsPointer	KEYWORD2
 isOverrun	KEYWORD2
-
+setHighPriorityScheduler	KEYWORD2
+currentScheduler	KEYWORD2
 #######################################
 # Constants (LITERAL1)
 TASK_SECOND	LITERAL1
@@ -76,5 +77,6 @@ _TASK_SLEEP_ON_IDLE_RUN	LITERAL1
 _TASK_STATUS_REQUEST	LITERAL1
 _TASK_WDT_IDS	LITERAL1
 _TASK_LTS_POINTER	LITERAL1
+_TASK_PRIORITY	LITERAL1
 #######################################
 

+ 2 - 2
library.properties

@@ -1,9 +1,9 @@
 name=TaskScheduler
-version=1.9.2
+version=2.0.0
 author=Anatoli Arkhipenko <arkhipenko@hotmail.com>
 maintainer=Anatoli Arkhipenko <arkhipenko@hotmail.com>
 sentence=A light-weight cooperative multitasking library for arduino microcontrollers.
-paragraph=Supports: periodic task execution (with dynamic execution period in milliseconds – frequency of execution), number of iterations (limited or infinite number of iterations), execution of tasks in predefined sequence, dynamic change of task execution parameters (frequency, number of iterations, callback methods), power saving via entering IDLE sleep mode when tasks are not scheduled to run, support for event-driven task invocation via Status Request object, support for task IDs and Control Points for error handling and watchdog timer, support for Local Task Storage pointer (allowing use of same callback code for multiple tasks)
+paragraph=Supports: periodic task execution (with dynamic execution period in milliseconds – frequency of execution), number of iterations (limited or infinite number of iterations), execution of tasks in predefined sequence, dynamic change of task execution parameters (frequency, number of iterations, callback methods), power saving via entering IDLE sleep mode when tasks are not scheduled to run, event-driven task invocation via Status Request object, task IDs and Control Points for error handling and watchdog timer, Local Task Storage pointer (allowing use of same callback code for multiple tasks), layered task prioritization.
 category=Timing
 url=https://github.com/arkhipenko/TaskScheduler.git
 architectures=*

+ 81 - 22
src/TaskScheduler.h

@@ -1,4 +1,4 @@
-// Cooperative multitasking library for Arduino version 1.9.0
+// Cooperative multitasking library for Arduino version 2.0.0
 // Copyright (c) 2015 Anatoli Arkhipenko
 //
 // Changelog:
@@ -73,6 +73,9 @@
 //    2015-11-28 - _TASK_ROLLOVER_FIX is deprecated (not necessary)
 //    2015-12-16 - bug fixes: automatic millis rollover support for delay methods
 //    2015-12-17 - new method for _TASK_TIMECRITICAL option: getStartDelay() 
+//
+// v2.0.0:
+//    2015-12-22 - _TASK_PRIORITY - support for layered task prioritization
 
 
 /* ============================================
@@ -115,6 +118,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_PRIORITY			// Support layered scheduling priority
  */
 
 #ifdef _TASK_SLEEP_ON_IDLE_RUN
@@ -162,6 +166,11 @@ typedef struct  {
 
 class Scheduler; 
 
+
+#ifdef _TASK_WDT_IDS
+	static unsigned int __task_id_counter = 0;		// global task ID counter for assiging task IDs automatically. 
+#endif
+
 class Task {
     friend class Scheduler;
     public:
@@ -218,14 +227,14 @@ class Task {
 		volatile unsigned long	iDelay; 			// actual delay until next execution (usually equal iInterval)
 		volatile unsigned long	iPreviousMillis;	// previous invocation time (millis).  Next invocation = iPreviousMillis + iInterval.  Delayed tasks will "catch up" 
 #ifdef _TASK_TIMECRITICAL
-		volatile long			iOverrun; 		// negative if task is "catching up" to it's schedule (next invocation time is already in the past)
-		volatile long			iStartDelay;	// actual execution of the task's callback method was delayed by this number of millis
+		volatile long			iOverrun; 			// negative if task is "catching up" to it's schedule (next invocation time is already in the past)
+		volatile long			iStartDelay;		// actual execution of the task's callback method was delayed by this number of millis
 #endif
 		volatile long			iIterations;		// number of iterations left. 0 - last iteration. -1 - infinite iterations
 		long					iSetIterations; 		// number of iterations originally requested (for restarts)
 		unsigned long			iRunCounter;		// current number of iteration (starting with 1). Resets on enable. 
 		void					(*iCallback)();		// pointer to the void callback method
-		bool					(*iOnEnable)();	// pointer to the bolol OnEnable callback method
+		bool					(*iOnEnable)();		// pointer to the bolol OnEnable callback method
 		void					(*iOnDisable)();	// pointer to the void OnDisable method
 		Task					*iPrev, *iNext;		// pointers to the previous and next tasks in the chain
 		Scheduler				*iScheduler;		// pointer to the current scheduler
@@ -237,20 +246,25 @@ class Task {
 		unsigned int			iControlPoint;		// current control point within the callback method. Reset to 0 by scheduler at the beginning of each pass
 #endif
 #ifdef _TASK_LTS_POINTER
-		void					*iLTS;			// pointer to task's local storage. Needs to be recast to appropriate type (usually a struct).
+		void					*iLTS;				// pointer to task's local storage. Needs to be recast to appropriate type (usually a struct).
 #endif
 };
 
+
+#ifdef _TASK_PRIORITY
+		static Scheduler* iCurrentScheduler;
+#endif
+
 class Scheduler {
 	friend class Task;
 	public:
 		Scheduler();
-		inline void init() { iFirst = NULL; iLast = NULL; iCurrent = NULL; }
+		void init();
 		void addTask(Task& aTask);
 		void deleteTask(Task& aTask);
-		void disableAll();
-		void enableAll();
-		void execute();
+		void disableAll(bool aRecursive = true);
+		void enableAll(bool aRecursive = true);
+		bool execute();			// Returns true if at none of the tasks' callback methods was invoked (true if idle run)
 		inline Task& currentTask() {return *iCurrent; }
 #ifdef _TASK_SLEEP_ON_IDLE_RUN
 		void allowSleep(bool aState = true) { iAllowSleep = aState; }
@@ -261,19 +275,23 @@ class Scheduler {
 #ifdef _TASK_TIMECRITICAL
 		inline bool isOverrun() { return (iCurrent->iOverrun < 0); }
 #endif
+#ifdef _TASK_PRIORITY
+		void setHighPriorityScheduler(Scheduler* aScheduler);
+		static Scheduler& currentScheduler() { return *(iCurrentScheduler); };
+#endif
 
 	private:
 		Task	*iFirst, *iLast, *iCurrent;			// pointers to first, last and current tasks in the chain
 #ifdef _TASK_SLEEP_ON_IDLE_RUN
 		bool	iAllowSleep;						// indication if putting avr to IDLE_SLEEP mode is allowed by the program at this time. 
 #endif
+#ifdef _TASK_PRIORITY
+		Scheduler *iHighPriority;					// Pointer to a higher priority scheduler
+#endif
 };
 
 
 // ------------------ TaskScheduler implementation --------------------
-#ifdef _TASK_WDT_IDS
-	static unsigned int __task_id_counter = 0;		// global task ID counter for assiging task IDs automatically. 
-#endif
 
 /** Constructor, uses default values for the parameters
  * so could be called with no parameters.
@@ -513,6 +531,17 @@ Scheduler::Scheduler() {
 #endif
 }
 
+/** Initializes all internal varaibles
+ */
+void Scheduler::init() { 
+	iFirst = NULL; 
+	iLast = NULL; 
+	iCurrent = NULL; 
+#ifdef _TASK_PRIORITY
+	iHighPriority = NULL;
+#endif
+}
+
 /** Appends task aTask to the tail of the execution chain.
  * @param &aTask - reference to the Task to be appended.
  * @note Task can only be part of the chain once.
@@ -569,43 +598,71 @@ void Scheduler::deleteTask(Task& aTask) {
 /** Disables all tasks in the execution chain
  * Convenient for error situations, when the only
  * task remaining active is an error processing task
+ * @param aRecursive - if true, tasks of the higher priority chains are disabled as well recursively
  */
-void Scheduler::disableAll() {
+void Scheduler::disableAll(bool aRecursive) {
 	Task	*current = iFirst;
 	while (current) {
 		current->disable();
 		current = current->iNext;
 	}
+#ifdef _TASK_PRIORITY
+	if (aRecursive && iHighPriority) iHighPriority->disableAll(aRecursive);
+#endif
 }
 
 
 /** Enables all the tasks in the execution chain
+ * @param aRecursive - if true, tasks of the higher priority chains are enabled as well recursively
  */
- void Scheduler::enableAll() {
+ void Scheduler::enableAll(bool aRecursive) {
 	Task	*current = iFirst;
 	while (current) {
 		current->enable();
 		current = current->iNext;
 	}
+#ifdef _TASK_PRIORITY
+	if (aRecursive && iHighPriority) iHighPriority->enableAll(aRecursive);
+#endif
 }
 
+/** Sets scheduler for the higher priority tasks (support for layered task priority)
+ * @param aScheduler - pointer to a scheduler for the higher priority tasks
+ */
+#ifdef _TASK_PRIORITY
+void Scheduler::setHighPriorityScheduler(Scheduler* aScheduler) {
+	if (aScheduler != this) iHighPriority = aScheduler;  // Setting yourself as a higher priority one will create infinite recursive call
+#ifdef _TASK_SLEEP_ON_IDLE_RUN
+	if (iHighPriority) {
+		iHighPriority->allowSleep(false);		// Higher priority schedulers should not do power management
+	}
+#endif
+};
+#endif
+
 /** Makes one pass through the execution chain.
  * Tasks are executed in the order they were added to the chain
  * There is no concept of priority
  * Different pseudo "priority" could be achieved
  * by running task more frequently 
  */
-void Scheduler::execute() {
-#ifdef _TASK_SLEEP_ON_IDLE_RUN
-	bool		idleRun = true;
-#endif
+bool Scheduler::execute() {
+	bool	 idleRun = true;
 	register unsigned long m, i;  // millis, interval;
 	
 	iCurrent = iFirst;
+	
+	while (iCurrent) {
+		
+#ifdef _TASK_PRIORITY
+	// If scheduler for higher priority tasks is set, it's entire chain is executed on every pass of the base scheduler
+		if (iHighPriority) idleRun = iHighPriority->execute() && idleRun; 
+		iCurrentScheduler = this;
+#endif
 
-	while (iCurrent) { 
-		do {   		
+		do {
 			if ( iCurrent->iStatus.enabled ) {
+
 #ifdef _TASK_WDT_IDS
 	// For each task the control points are initialized to avoid confusion because of carry-over:
 				iCurrent->iControlPoint = 0;
@@ -618,6 +675,7 @@ void Scheduler::execute() {
 				}
 				m = millis();
 				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 
@@ -633,6 +691,7 @@ void Scheduler::execute() {
 					iCurrent->iStatus.waiting = 0;
 				}
 #endif
+
 				if ( m - iCurrent->iPreviousMillis < iCurrent->iDelay ) break;
 
 				if ( iCurrent->iIterations > 0 ) iCurrent->iIterations--;  // do not decrement (-1) being a signal of never-ending task
@@ -650,9 +709,7 @@ void Scheduler::execute() {
 				iCurrent->iDelay = i;
 				if ( iCurrent->iCallback ) {
 					( *(iCurrent->iCallback) )();
-#ifdef _TASK_SLEEP_ON_IDLE_RUN
 					idleRun = false;
-#endif
 				}
 			}
 		} while (0); 	//guaranteed single run - allows use of "break" to exit 
@@ -670,6 +727,8 @@ void Scheduler::execute() {
 	  sleep_disable(); /* First thing to do is disable sleep. */
 	}
 #endif
+
+	return (idleRun);
 }