aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatoli Arkhipenko <arkhipenko@hotmail.com>2015-12-23 17:04:21 -0500
committerAnatoli Arkhipenko <arkhipenko@hotmail.com>2015-12-23 17:12:06 -0500
commit965f1b768d3d0675e2483ca62fa6d0565c389a31 (patch)
tree8bae4e1eee8275efaab252b35cb26c6a304fb015
parent42d8d776e3fdb3c48700a3d88c8615dbf81da23f (diff)
Version 2.0.0 support for layered task prioritizationv2.0.0
* _TASK_PRIORITY - support for layered task prioritization
-rw-r--r--README12
-rw-r--r--examples/Scheduler_example01/Scheduler_example01.ino (renamed from examples/Scheduler_example1/Scheduler_example1.ino)0
-rw-r--r--examples/Scheduler_example02/Scheduler_example02.ino (renamed from examples/Scheduler_example2/Scheduler_example2.ino)0
-rw-r--r--examples/Scheduler_example03/Scheduler_example03.ino (renamed from examples/Scheduler_example3/Scheduler_example3.ino)0
-rw-r--r--examples/Scheduler_example04_StatusRequest/Scheduler_example04_StatusRequest.ino (renamed from examples/Scheduler_example4_StatusRequest/Scheduler_example4_StatusRequest.ino)0
-rw-r--r--examples/Scheduler_example05_StatusRequest/Scheduler_example05_StatusRequest.ino (renamed from examples/Scheduler_example5_StatusRequest/Scheduler_example5_StatusRequest.ino)0
-rw-r--r--examples/Scheduler_example06_IDLE/Scheduler_example06_IDLE.ino (renamed from examples/Scheduler_example6_IDLE/Scheduler_example6_IDLE.ino)0
-rw-r--r--examples/Scheduler_example07_WDT/Scheduler_example07_WDT.ino (renamed from examples/Scheduler_example7_WDT/Scheduler_example7_WDT.ino)0
-rw-r--r--examples/Scheduler_example08_LTS/Scheduler_example08_LTS.ino (renamed from examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino)0
-rw-r--r--examples/Scheduler_example09_TimeCritical/Scheduler_example09_TimeCritical.ino (renamed from examples/Scheduler_example9_TimeCritical/Scheduler_example9_TimeCritical.ino)0
-rw-r--r--examples/Scheduler_example11_Priority/Scheduler_example11_Priority.ino105
-rw-r--r--examples/Scheduler_example12_Priority/Scheduler_example12_Priority.ino136
-rw-r--r--extras/TaskScheduler.docbin157696 -> 177152 bytes
-rw-r--r--extras/TaskScheduler.html599
-rw-r--r--keywords.txt4
-rw-r--r--library.properties4
-rw-r--r--src/TaskScheduler.h103
17 files changed, 790 insertions, 173 deletions
diff --git a/README b/README
index c6e66a5..4012206 100644
--- a/README
+++ b/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
diff --git a/examples/Scheduler_example1/Scheduler_example1.ino b/examples/Scheduler_example01/Scheduler_example01.ino
index 2175e57..2175e57 100644
--- a/examples/Scheduler_example1/Scheduler_example1.ino
+++ b/examples/Scheduler_example01/Scheduler_example01.ino
diff --git a/examples/Scheduler_example2/Scheduler_example2.ino b/examples/Scheduler_example02/Scheduler_example02.ino
index c76551a..c76551a 100644
--- a/examples/Scheduler_example2/Scheduler_example2.ino
+++ b/examples/Scheduler_example02/Scheduler_example02.ino
diff --git a/examples/Scheduler_example3/Scheduler_example3.ino b/examples/Scheduler_example03/Scheduler_example03.ino
index 115f7bc..115f7bc 100644
--- a/examples/Scheduler_example3/Scheduler_example3.ino
+++ b/examples/Scheduler_example03/Scheduler_example03.ino
diff --git a/examples/Scheduler_example4_StatusRequest/Scheduler_example4_StatusRequest.ino b/examples/Scheduler_example04_StatusRequest/Scheduler_example04_StatusRequest.ino
index 22f1dbc..22f1dbc 100644
--- a/examples/Scheduler_example4_StatusRequest/Scheduler_example4_StatusRequest.ino
+++ b/examples/Scheduler_example04_StatusRequest/Scheduler_example04_StatusRequest.ino
diff --git a/examples/Scheduler_example5_StatusRequest/Scheduler_example5_StatusRequest.ino b/examples/Scheduler_example05_StatusRequest/Scheduler_example05_StatusRequest.ino
index 013c356..013c356 100644
--- a/examples/Scheduler_example5_StatusRequest/Scheduler_example5_StatusRequest.ino
+++ b/examples/Scheduler_example05_StatusRequest/Scheduler_example05_StatusRequest.ino
diff --git a/examples/Scheduler_example6_IDLE/Scheduler_example6_IDLE.ino b/examples/Scheduler_example06_IDLE/Scheduler_example06_IDLE.ino
index eb75a88..eb75a88 100644
--- a/examples/Scheduler_example6_IDLE/Scheduler_example6_IDLE.ino
+++ b/examples/Scheduler_example06_IDLE/Scheduler_example06_IDLE.ino
diff --git a/examples/Scheduler_example7_WDT/Scheduler_example7_WDT.ino b/examples/Scheduler_example07_WDT/Scheduler_example07_WDT.ino
index 60983bd..60983bd 100644
--- a/examples/Scheduler_example7_WDT/Scheduler_example7_WDT.ino
+++ b/examples/Scheduler_example07_WDT/Scheduler_example07_WDT.ino
diff --git a/examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino b/examples/Scheduler_example08_LTS/Scheduler_example08_LTS.ino
index 8d8df06..8d8df06 100644
--- a/examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino
+++ b/examples/Scheduler_example08_LTS/Scheduler_example08_LTS.ino
diff --git a/examples/Scheduler_example9_TimeCritical/Scheduler_example9_TimeCritical.ino b/examples/Scheduler_example09_TimeCritical/Scheduler_example09_TimeCritical.ino
index b330d6f..b330d6f 100644
--- a/examples/Scheduler_example9_TimeCritical/Scheduler_example9_TimeCritical.ino
+++ b/examples/Scheduler_example09_TimeCritical/Scheduler_example09_TimeCritical.ino
diff --git a/examples/Scheduler_example11_Priority/Scheduler_example11_Priority.ino b/examples/Scheduler_example11_Priority/Scheduler_example11_Priority.ino
new file mode 100644
index 0000000..ad251f5
--- /dev/null
+++ b/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();
+
+}
diff --git a/examples/Scheduler_example12_Priority/Scheduler_example12_Priority.ino b/examples/Scheduler_example12_Priority/Scheduler_example12_Priority.ino
new file mode 100644
index 0000000..4d850dc
--- /dev/null
+++ b/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();
+
+}
diff --git a/extras/TaskScheduler.doc b/extras/TaskScheduler.doc
index 8562125..e6e4f3e 100644
--- a/extras/TaskScheduler.doc
+++ b/extras/TaskScheduler.doc
Binary files differ
diff --git a/extras/TaskScheduler.html b/extras/TaskScheduler.html
index 699c110..5c5edc8 100644
--- a/extras/TaskScheduler.html
+++ b/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
@@ -2798,6 +3032,83 @@ V1 = *((sensor_data*) ts.currentLts());</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; 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>
</OL>
@@ -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> \ No newline at end of file
+</HTML>
diff --git a/keywords.txt b/keywords.txt
index df63872..aa73279 100644
--- a/keywords.txt
+++ b/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
#######################################
diff --git a/library.properties b/library.properties
index 834a433..5e4b6c3 100644
--- a/library.properties
+++ b/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=*
diff --git a/src/TaskScheduler.h b/src/TaskScheduler.h
index a655ec7..610ca75 100644
--- a/src/TaskScheduler.h
+++ b/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);
}