aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatoli Arkhipenko <arkhipenko@hotmail.com>2015-10-29 23:39:52 -0400
committerAnatoli Arkhipenko <arkhipenko@hotmail.com>2015-11-03 13:59:13 -0500
commitef2329bdeade723f560cd0f7e933c9f3119677f3 (patch)
tree8ec69af2ba7e74d9577f9daccefce7325590b58e
parentccd1047d0286027ff98ee7f1dfdfa1f9d5e6e4e3 (diff)
TaskScheduler v1.8.2 Local Task Storage and bug fixesv1.8.2
* implemented Local Task Storage Pointer (allow use of same callback code for different tasks) * bug fix: currentTask() method returns incorrect Task reference if called within OnEnable and OnDisable methods * protection against infinite loop in OnEnable (if enable() methods are called within OnEnable) * new currentLts() method in the scheduler class returns current task's LTS pointer in one call
-rw-r--r--README10
-rw-r--r--examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino142
-rw-r--r--extras/TaskScheduler.docbin135680 -> 172544 bytes
-rw-r--r--extras/TaskScheduler.html631
-rw-r--r--keywords.txt3
-rw-r--r--library.properties6
-rw-r--r--src/TaskScheduler.h133
7 files changed, 683 insertions, 242 deletions
diff --git a/README b/README
index be621bb..1a8139b 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
Task Scheduler – cooperative multitasking for Arduino microcontrollers
-Version 1.8.1: 2015-10-22
+Version 1.8.2: 2015-10-29
OVERVIEW:
@@ -11,7 +11,7 @@ A lightweight implementation of cooperative multitasking (task scheduling) suppo
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)
Changelog:
v1.0.0:
@@ -56,3 +56,9 @@ v1.8.0:
v1.8.1:
2015-10-22 - implement Task id and control points to support identification of failure points for watchdog timer logging
+v1.8.2:
+ 2015-10-27 - implement Local Task Storage Pointer (allow use of same callback code for different tasks)
+ 2015-10-27 - bug: currentTask() method returns incorrect Task reference if called within OnEnable and OnDisable methods
+ 2015-10-27 - protection against infinite loop in OnEnable (if enable() methods are called within OnEnable)
+ 2015-10-29 - new currentLts() method in the scheduler class returns current task's LTS pointer in one call
+
diff --git a/examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino b/examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino
new file mode 100644
index 0000000..238617e
--- /dev/null
+++ b/examples/Scheduler_example8_LTS/Scheduler_example8_LTS.ino
@@ -0,0 +1,142 @@
+/**
+ * TaskScheduler Test sketch - use of task's Local Task Storage pointer
+ * Test case:
+ * Overall test runs for 5 seconds
+ * A number of calculator tasks run every one second, and update their respective variables using Local Task Storage pointer
+ * All calculator tasks use the same callback code, which obtains reference to appropriate variables via LTS pointer
+ * Calculaotr tasks perform simple calculation (as an example):
+ * adding task id number to itself
+ * multiplying task id number by 10
+ *
+ * Upon completion of the overall test, all results are printed out.
+ * Test could be repeated with various number of calculator tasks.
+ * All that needs to change is data definitions - code is completely agnostic of number of tasks
+ */
+
+#define _TASK_SLEEP_ON_IDLE_RUN // Compile with support for entering IDLE SLEEP state for 1 ms if not tasks are scheduled to run
+#define _TASK_WDT_IDS // Compile with support for Task IDs and Watchdog timer
+#define _TASK_LTS_POINTER // Compile with support for Local Task Storage pointer
+#include <TaskScheduler.h>
+
+// Overall number of calculator tasks:
+#define NO_TASKS 3
+
+Scheduler ts;
+
+// Calculator tasks.
+// Note that all three tasks use the same callback methods
+// They will be updating specific variables based on the
+// Locat Task Storage pointers
+Task t1(1000, -1, &Calculate, &ts, false, &CalcOn);
+Task t2(1000, -1, &Calculate, &ts, false, &CalcOn);
+Task t3(1000, -1, &Calculate, &ts, false, &CalcOn);
+// add more calc tasks here if necessary
+
+Task tWrapper(5000, 1, NULL, &ts, false, &WrapperOn, &WrapperOff);
+
+// The below structure is an object referenced by LTS pointer
+typedef struct {
+ unsigned int id;
+ long sum;
+ long product;
+} task_var;
+
+// These are actual structures which hold tasks specific values
+task_var v1;
+task_var v2;
+task_var v3;
+
+// Arrays below allow indexed access to specific tasks and tasks variables
+Task *tasks[] = { &t1, &t2, &t3 };
+task_var *vars[] = { &v1, &v2, &v3 };
+
+
+/**
+ * This method is called when a wrapper task is enabled
+ * The purpose is to supply LTS pointers to all the tasks
+ */
+bool WrapperOn() {
+
+ for (int i=0; i < NO_TASKS; i++) {
+ Task& T = *tasks[i];
+ T.setLtsPointer( vars[i] );
+ T.enableDelayed();
+ }
+
+ return true; // Signal that Task could be enabled
+}
+
+/**
+ * This method is called when Wrapper task is disabled (after first and only iteration is executed)
+ * For each of the calculor tasks the results are printed out.
+ */
+void WrapperOff() {
+ Serial.println("Finished processing");
+
+ ts.disableAll();
+
+ for (int i=0; i < NO_TASKS; i++) {
+ Serial.print("ID: "); Serial.println(vars[i]->id);
+ Serial.print("Sum: "); Serial.println(vars[i]->sum);
+ Serial.print("Product: "); Serial.println(vars[i]->product);
+ Serial.println();
+ }
+}
+
+
+/**
+ * This method is executed when each calculator task is enabled
+ * The purpose is to initiate all local variables
+ */
+bool CalcOn() {
+ Task& T = ts.currentTask();
+ task_var& var = *((task_var*) T.getLtsPointer());
+
+// Initialize local variables
+ var.id = T.getId();
+ var.sum = 0;
+ var.product = var.id;
+
+ return true;
+}
+
+
+/**
+ * This method performs simple calculations on task's local variables
+ */
+void Calculate() {
+ Task& T = ts.currentTask();
+// Another way to get to LTS pointer:
+ task_var& var = *((task_var*) ts.currentLts());
+
+
+ Serial.print("Calculating for task: ");
+ Serial.print(T.getId());
+ Serial.print("; Task id per LTS is: ");
+ Serial.println( var.id );
+
+ var.sum += T.getId();
+ var.product = var.product * 10;
+
+}
+
+
+/**
+ * Standard Arduino setup and loo methods
+ */
+void setup() {
+ Serial.begin(115200);
+
+ randomSeed(analogRead(0)+analogRead(5));
+
+ pinMode(13, OUTPUT);
+ digitalWrite(13, LOW);
+
+ Serial.println("Local Task Storage pointer test");
+
+ tWrapper.enableDelayed();
+}
+
+void loop() {
+ ts.execute();
+}
diff --git a/extras/TaskScheduler.doc b/extras/TaskScheduler.doc
index bffaa97..9995a43 100644
--- a/extras/TaskScheduler.doc
+++ b/extras/TaskScheduler.doc
Binary files differ
diff --git a/extras/TaskScheduler.html b/extras/TaskScheduler.html
index ac779a7..651a927 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="20151022;23060000">
+ <META NAME="CHANGED" CONTENT="20151029;23230000">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
@@ -16,17 +16,19 @@
@page { margin: 0.79in }
P { margin-bottom: 0.08in; direction: ltr; color: #000000; widows: 0; orphans: 0 }
P.western { font-family: "Liberation Serif", "MS PMincho", serif; font-size: 12pt; so-language: en-US }
- P.cjk { font-family: "WenQuanYi Micro Hei", "MS Mincho"; font-size: 12pt; so-language: zh-CN }
+ P.cjk { font-family: "WenQuanYi Micro Hei", "MS Mincho"; font-size: 12pt }
P.ctl { font-family: "Lohit Hindi", "MS Mincho"; font-size: 12pt; so-language: hi-IN }
A:link { color: #0000ff }
-->
</STYLE>
</HEAD>
<BODY LANG="en-US" TEXT="#000000" LINK="#0000ff" BGCOLOR="#ffffff" DIR="LTR">
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>Task Scheduler –
-cooperative multitasking for Arduino microcontrollers</B></P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>Version 1.8.1:
-2015-10-21</B></P>
+<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
+multitasking for Arduino microcontrollers</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in; border-top: none; border-bottom: 1px solid #000000; border-left: none; border-right: none; padding-top: 0in; padding-bottom: 0.01in; padding-left: 0in; padding-right: 0in">
+<FONT SIZE=2 STYLE="font-size: 11pt"><B>Version 1.8.2: 2015-10-27</B></FONT></P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>OVERVIEW</B>:</P>
@@ -35,20 +37,24 @@ implementation of cooperative multitasking (task scheduling)
supporting:</P>
<OL>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">Periodic task
- execution (with dynamic execution period in milliseconds)</P>
+ execution (with dynamic execution period in milliseconds –
+ frequency of execution)</P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">Number of
- iterations (n times)</P>
+ iterations (limited or infinite number of iterations)</P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">Execution of tasks
in predefined sequence</P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">Dynamic change of
task execution parameters (frequency, number of iterations, callback
- function)</P>
+ methods)</P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">Power saving via
- entering IDLE sleep mode between tasks are scheduled to run</P>
- <LI><P CLASS="western" STYLE="margin-bottom: 0in">Support for task
- invocation via Status Request object</P>
+ entering IDLE sleep mode when tasks are not scheduled to run</P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">Support for
+ event-driven task invocation via Status Request object</P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">Support for task
IDs and Control Points for error handling and watchdog timer</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>
</OL>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
@@ -56,45 +62,75 @@ supporting:</P>
<P CLASS="western" STYLE="margin-bottom: 0in">“Task” is a
container concept that links together:</P>
<OL>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">Program code
+ performing specific task activities (callback methods)</P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">Execution interval</P>
- <LI><P CLASS="western" STYLE="margin-bottom: 0in">Execution event
- (Status Request)</P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">Number of
execution iterations</P>
- <LI><P CLASS="western" STYLE="margin-bottom: 0in">Piece of code
- performing task activities (callback functions)</P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">(Optionally)
+ Execution event (Status Request)</P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">(Optionally)
+ Pointer to a Local Task Storage area</P>
</OL>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>Tasks</B> are linked
-into execution <B>chains</B>, which are processed by the “Scheduler”
-in the order they are linked.</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Tasks</B> perform
+certain functions, which could require periodic or one-time
+execution, update of specific variables, or waiting for specific
+events. Tasks also could be controlling specific hardware, or
+triggered by hardware interrupts.
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">For execution purposes
+<B>Tasks</B> are linked into execution <B>chains</B>, which are
+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">Each task performs its
-function via callback function. Scheduler calls Task’s callback
-function periodically until task is disabled or task runs out of
-iterations. In addition to “regular” callback, two methods could
-be enabled for each task: a callback function invoked once when task
-is enabled, and a callback function invoked once when the task is
-disabled. Those two special methods allows task to properly initiate
-themselves for execution and clean-up after execution is over.
+function via a callback method. Scheduler calls Task’s callback
+method periodically until task is disabled or runs out of iterations.
+In addition to “regular” callback method, two additional methods
+could be utilized for each task: a callback method invoked every time
+the task is enabled, and a callback method invoked once when the task
+is disabled. Those two special methods allow tasks to properly
+initiate themselves for execution, and clean-up after execution is
+over (E.g., setup pin modes on enable, and always bring pin level to
+LOW at the end).
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in">Tasks are responsible
for supporting <B>cooperative</B> <B>multitasking</B> by being “good
-neighbors”, i.e., running their callback functions quickly in a
-non-blocking way and releasing control as soon as possible.
+neighbors”, i.e., running their callback methods quickly in a
+non-blocking way, and releasing control back to scheduler as soon as
+possible.
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in">“Scheduler” is
-executing Tasks' callback functions in the order the tasks were added
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>Scheduler</B> is
+executing Tasks' callback methods in the order the tasks were added
to the chain, from first to last. Scheduler stops and exists after
processing the chain once in order to allow other statements in the
-main code of <B>loop()</B> function to run. This <B>a “scheduling
-pass”.</B></P>
+main code of <B>loop()</B> method to run. This is referred to as a
+<B>“scheduling pass”.</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in">(Normally, there is no
+need to have any other statements in the <B>loop</B>() method other
+than the Scheduler's <B>execute</B>() method).</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<B>Below is the flowchart of a Task lifecycle:</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><IMG SRC="TaskScheduler_html.png" NAME="graphics1" ALIGN=BOTTOM WIDTH=664 HEIGHT=690 BORDER=0></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><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>
+TaskScheduler.h header file. Specifically:</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in">If compiled with
@@ -103,15 +139,11 @@ enabled, the scheduler will place processor into IDLE sleep mode (for
approximately 1 ms, as the timer interrupt will wake it up), after
what is determined to be an “idle” pass. An Idle Pass is a pass
through the task chain when no Tasks were scheduled to run their
-callback functions. This is done to avoid repetitive empty passes
+callback methods. This is done to avoid repetitive idle passes
through the chain when no tasks need to be executed. If any of the
tasks in the chain always requires immediate execution (aInterval =
-0), then there will be no IDLE sleep between task callback execution.</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
-</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=747 BORDER=0></P>
+0), then there will be no IDLE sleep between task's callback method
+execution.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Task
@@ -125,15 +157,16 @@ their internal time scheduling variables to the new value of
“frozen”, i.e., if a task was scheduled to run in 1 second from
now, and device was put to sleep for 5 minutes, upon wake up, the
task will still be scheduled 1 second from the time of wake up.
-Executing <B>enable() </B>function on this tasks will make it run as
+Executing <B>enable() </B>method on this tasks will make it run as
soon as possible. This is a concern only for tasks which are required
to run in a truly periodical manner (in absolute time terms).
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in">In addition to
-time-only invocation, tasks can be scheduled to wait on an event
-employing StatusRequest objects (more about Status Requests later).</P>
+time-only (<B>millis</B>() only) invocation, tasks can be scheduled
+to wait on an event employing StatusRequest objects (more about
+Status Requests later).</P>
<P CLASS="western" STYLE="margin-bottom: 0in">Consider a scenario
when one task (t1) is performing a function which affects execution
of many tasks (t2, t3). In this case the task t1 will “signal”
@@ -149,17 +182,17 @@ t1 is invoked.
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in">Please see the examples
-at the end of this document.</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">Please see the code
+examples at the end of this document, and included with the library
+package for details.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>COMPILE PARAMETERS:</B></P>
<P CLASS="western" STYLE="margin-bottom: 0in">This library could be
-compiled with several options.
-</P>
-<P CLASS="western" STYLE="margin-bottom: 0in">These parameters must
-be defined before inclusion of the library header file into the
-sketch.</P>
+compiled in several configurations.</P>
+<P CLASS="western" STYLE="margin-bottom: 0in">Parameters (<B>#define</B>s)
+defining what functionality should or should not be included need be
+defined before the library header file in the body of arduino sketch.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in">#define
@@ -168,15 +201,15 @@ sketch.</P>
library with time critical tracking option enabled.</P>
<P CLASS="western" STYLE="margin-bottom: 0in">Time critical option
keeps track where next execution time of the task falls, and makes it
-available via API through Task::<B> getOverrun() </B>function. If
+available via API through <B>Task::getOverrun()</B> method. If
<B>getOverrun </B>returns a negative value, this Task’s next
-execution time is in the past, and task is behind schedule. This most
-probably means that either task’s callback function runtime is too
-long, or the execution interval is too short (then schedule is too
-aggressive).</P>
+execution time point is <I>already</I> in the past, and task is
+behind schedule. This most probably means that either task’s
+callback method's runtime is too long, or the execution interval is
+too short (and therefore schedule is too aggressive).</P>
<P CLASS="western" STYLE="margin-bottom: 0in">A positive value
-indicates that task is on schedule, and callback functions have
-enough time to finish before the next scheduled pass.
+indicates that task is on schedule, and callback methods have enough
+time to finish before the next scheduled pass.
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
@@ -186,14 +219,15 @@ enough time to finish before the next scheduled pass.
library with the <B>sleep</B> option enabled (AVR boards only).</P>
<P CLASS="western" STYLE="margin-bottom: 0in">When enabled, scheduler
will put the microcontroller into <B>SLEEP_MODE_IDLE</B> state if
-none of the tasks’ callback functions were activated during pass.
-<B>IDLE</B> state is interrupted by timers once every 1 ms. Helps
-conserve power. Device in SLEEP_MODE_IDLE wakes up to all hardware
-and timer interrupts, so scheduling is kept current.</P>
+none of the tasks’ callback methods were activated during execution
+pass. <B>IDLE</B> state is interrupted by timers once every 1 ms.
+Putting microcontroller to IDLE state helps conserve power. Device
+in SLEEP_MODE_IDLE wakes up to all hardware and timer interrupts, so
+scheduling is kept current.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in">#define
-<B>_TASK_STATUS_REQUEST</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+#define <B>_TASK_STATUS_REQUEST</B></P>
<P CLASS="western" STYLE="margin-bottom: 0in">…will compile
TaskScheduler with support for StatusRequest object. Status Requests
are objects allowing tasks to wait on an event, and signal event
@@ -203,7 +237,7 @@ completion to each other.
</P>
<P CLASS="western" STYLE="margin-bottom: 0in">#define <B>_TASK_WDT_IDS</B></P>
<P CLASS="western" STYLE="margin-bottom: 0in">…will compile
-TaskScheduler with support for Task Ids and Control Points. Each task
+TaskScheduler with support for Task IDs and Control Points. Each task
can be (and is by default) assigned an ID, which could be used to
identify the task in case there is a problem with it. Furthermore
within the task, Control Points could be defined to further help with
@@ -223,30 +257,44 @@ task id. <B>Task ids are unsigned integers.</B></P>
a way to identify potential problem points within a task. Control
points are <B>unsigned integers </B>as well. Please note that there
is only one control point per task, and it is set to zero when the
-task’s callback function is invoked (this is done to prevent
-“stray” control point from previous task(s) confusing the
-matters.</P>
+task’s callback method is invoked (this is done to prevent “stray”
+control point from previous task(s) confusing the matters.</P>
<P CLASS="western" STYLE="margin-bottom: 0in">Example #7 contains a
test of task ID and control points functionality.
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><B>NOTE: above
-parameters are DISABLED by default, and need to be explicitly
-enabled.</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in">#define
+<B>_TASK_LTS_POINTER</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in">…will compile
+TaskScheduler with support for Local Task Storage pointer (LTS). LTS
+is a generic (void*) pointer which could be set to reference a
+variable or a structure specific to a particular task. A callback
+method can get access to specific variables by getting reference to a
+currently running task from the scheduler, and then casting (void*)
+LTS pointer to the appropriate pointer type.
+</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>NOTE: </B>above
+parameters are<B> DISABLED </B>by default, and need to be explicitly
+enabled by placing appropriate #define statements in front of the
+#include statement for the TaskScheduler header file.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><FONT SIZE=4><B>API
-DOCUMENTATION:</B></FONT></P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<FONT SIZE=4><B>API DOCUMENTATION:</B></FONT></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">
<FONT SIZE=4><B>TASKS:</B></FONT></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-bottom: 0in">CREATION:</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>Task();</B></P>
@@ -258,7 +306,7 @@ constructor.
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes
no parameters and creates a task that could be scheduled to run at
every scheduling pass indefinitely, but does not have a callback
-function defined, so no execution will actually take place.
+method defined, so no code execution will actually take place.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">All
tasks are created <B>disabled</B> by default.</P>
@@ -268,14 +316,14 @@ tasks are created <B>disabled</B> by default.</P>
<B>Task(unsigned long aInterval, long aIterations, void
(*aCallback)(), Scheduler* aScheduler, bool aEnable, bool
(*aOnEnable)(), void (*aOnDisable)())</B></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Constructor
with parameters.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Creates
a task that is scheduled to run every &lt;aInterval&gt; milliseconds,
-&lt;aIterations&gt; times, executing &lt;aCallback&gt; function on
+&lt;aIterations&gt; times, executing &lt;aCallback&gt; method on
every pass.
</P>
<OL>
@@ -290,7 +338,7 @@ every pass.
all their iterations remain active.
</P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">aCallback is a
- pointer to a void callback function without parameters (<B>default =
+ pointer to a void callback method without parameters (<B>default =
NULL)</B></P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">aScheduler –
<B>optional</B> reference to existing scheduler. If supplied (not
@@ -300,23 +348,37 @@ every pass.
<B>optional</B>. Value of <B>true </B>will create task enabled.
(<B>default = false)</B></P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">aOnEnable is a
- pointer to a bool callback function without parameters, invoked when
- task is enabled. If OnEnable function returns <B>true</B>, task is
- enabled. If <B>OnEnable</B> function return <B>false</B>, task
- remains disabled (<B>default = NULL)</B></P>
+ pointer to a bool callback method without parameters, invoked when
+ task is enabled. If OnEnable method returns <B>true</B>, task is
+ enabled. If <B>OnEnable</B> method return <B>false</B>, task remains
+ disabled (<B>default = NULL)</B></P>
<LI><P CLASS="western" STYLE="margin-bottom: 0in">aOnDisable is a
- pointer to a void callback function without parameters, invoked when
+ pointer to a void callback method without parameters, invoked when
task is disabled (<B>default = NULL)</B></P>
</OL>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">All
-tasks are created <B>disabled</B> by default (unless aEnable = true).
-You have to explicitly enable the task for execution.</P>
+tasks are created <B>disabled</B> by default (unless <B>aEnable</B> =
+true). You have to explicitly enable the task for execution.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE:
+</B>OnEnable callback method is called immediately when task is
+enabled, which could be well ahead of the scheduled execution time of
+the task. Please bear that in mind – other tasks, hardware, serial
+interface may not even be initialized yet. It is always advisable to
+explicitly enable tasks with OnEnable methods after all
+initialization methods completed (e.g., at the end of <B>setup</B>()
+method)
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enabled
-task is scheduled for execution immediately. Enable tasks with delay
-(standard execution interval or specific execution interval) in order
-to defer first run of the task.</P>
+task is scheduled for execution as soon as the Scheduler's <B>execute</B>()
+methods gets control. In order to delay first run of the task, use
+<B>enableDelayed</B> or <B>delay</B> method (for enabled tasks)
+method.</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">
@@ -328,12 +390,13 @@ to defer first run of the task.</P>
compiled with support for Status Request objects, this constructor
creates a Task for activation on event (since such tasks must run
<B>waitFor() </B>method, their <I>interval</I>, <I>iteration</I> and
-<I>enabled</I> status will be set by that method.</P>
+<I>enabled</I> status will be set by that method (<I>to 0, 1 and
+false</I> respectively).</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>INFORMATION</B></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">The
-following 3 “getter” functions return task status
+following 3 “getter” methods return task status
(enabled/disabled), execution interval in milliseconds, number of
<I><B>remaining</B></I> iterations.
</P>
@@ -354,10 +417,10 @@ getIterations() </B>
library is compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
enabled, tasks are monitored for “long running” scenario. A “long
running” task is a task that does not finish processing its
-callback functions quickly, and thus creates a situation for itself
-and other tasks where they don't run on a scheduled interval, but
-rather “catch up” and are behind. When task scheduler sets the
-next execution target time, it adds Task's execution interval to the
+callback methods quickly, and thus creates a situation for itself and
+other tasks where they don't run on a scheduled interval, but rather
+“catch up” and are behind. When task scheduler sets the next
+execution target time, it adds Task's execution interval to the
previously scheduled execution time:</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> <B>next
execution time = previous execution time + task execution interval</B></P>
@@ -366,10 +429,10 @@ execution time = previous execution time + task execution interval</B></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
<B>next execution time</B> happens to be already in the past (<B>next
execution time</B> &lt; <B>millis()</B>), then task is considered
-<I><B>overrun</B></I>. <B>GetOverrun</B> function returns number of
+<I><B>overrun</B></I>. <B>GetOverrun</B> method returns number of
milliseconds between next execution time and current time. If the
-<B>value is negative</B>, the task is overrun by that many
-milliseconds.
+<B>value is negative</B>, the task has overrun (cut into the) next
+execution interval by that many milliseconds.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Positive
value indicate number of milliseconds of slack this task has for
@@ -381,13 +444,13 @@ execution purposes.
getRunCounter()</B></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
the number of the current run. “Current run” is the number of
-times a callback function has been invoked since the last time a task
+times a callback method has been invoked since the last time a task
was enabled. <BR><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE:
</B>The <B>runCounter</B> value is incremented <I>before</I> callback
-function is invoked. If a task is checking the <B>runCounter</B>
-value within its callback function, then the first run value is 1.
+method is invoked. If a task is checking the <B>runCounter</B> value
+within its callback method, then the first run value is 1.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
task T1 is checking the <B>runCounter</B> value of another task (T2)
@@ -399,13 +462,13 @@ value = 1 indicates that T2 has run once.
<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool
isFirstIteration()</B></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Indicates
-whether current pass is a first iteration of the task.
+whether current pass is (or will be) a first iteration of the task.
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool
isLastIteration()</B></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">For
-tasks with a limited number of iterations only, indicates whether
-current pass is the last iteration.
+tasks with a l<I>imited number of iterations only</I>, indicates
+whether current pass is the last iteration.
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
@@ -426,12 +489,20 @@ is a task which was enabled and requires execution.
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
-</B>enable() invokes task’s <B>OnEnable</B> method (if not NULL),
-which can prepare task for execution. <B>OnEnable</B> must return a
-value of <B>true</B> for task to be enabled. If <B>OnEnable</B>
-returns <B>false</B>, task remains disabled. <B>OnEnable</B> is
-invoked every time <B>enable</B> is called, regardless if task is
-already enabled or not.
+</B>enable() invokes task’s <B>OnEnable</B> method (if not NULL)
+<B>immediately</B>, which can prepare task for execution. <B>OnEnable</B>
+must return a value of <B>true</B> for task to be enabled. If
+<B>OnEnable</B> returns <B>false</B>, task remains disabled.
+<B>OnEnable</B> is invoked every time <B>enable</B> is called,
+regardless if task is already enabled or not.
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE:</B>
+in the event enable() method is called inside the OnEnable callback
+method (thus basically creating indefinte loop), TaskScheduler will
+only call OnEnable once (thus protecting the Task against OnEnable
+infinite loop).
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
@@ -441,7 +512,10 @@ already enabled or not.
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables
the task only if it was previously disabled. Returns previous enable
state: <B>true</B> if task was already enabled, and <B>false</B> if
-task was disabled.</P>
+task was disabled. Since <B>enable() </B>schedules Task for execution
+immediately, this method provides a way to activate tasks and
+schedule them for immediate execution only if they are not active
+already.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>void delay();</B></P>
@@ -453,7 +527,7 @@ the enabled/disabled status of the task.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE:
</B>a delay of 0 (zero) will delay task for current execution
interval. Use <B>forceNextIteration() </B>method to force execution
of the task’s callback during immediate next scheduling pass.
@@ -480,7 +554,8 @@ enableDelayed();</B></P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables
-the task, and schedules it for execution after a delay (aInterval).
+the task, and schedules it for execution after task's current
+scheduling interval (aInterval).
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
@@ -498,10 +573,9 @@ the task, and schedules it for execution after a specific delay
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">For
-tasks with limited number of iterations only, <B>restart</B> function
-will re-enable the task, set the number of iterations back to when
-the task was created and and schedule the task for execution as soon
-as possible.</P>
+tasks with limited number of iterations only, <B>restart</B> method
+will re-enable the task, set the number of iterations back to last
+set value, and schedule task for execution as soon as possible.</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>void restartDelayed
@@ -509,8 +583,8 @@ as possible.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Same
-as <B>restart() </B>function, with the only difference being that
-Task is scheduled to run first iteration after a delay = <B>aDelay</B>
+as <B>restart()</B> method, with the only difference being that Task
+is scheduled to run first iteration after a delay = <B>aDelay</B>
milliseconds.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
@@ -519,15 +593,17 @@ milliseconds.</P>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Disables
the task. Scheduler will not execute this task any longer, even if it
-remains in the chain. Task can be later re-enabled for execution.
+remains in the chain. Task <B>can</B> be later re-enabled for
+execution.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Return
previous enabled state: <B>true</B> if task was enabled prior to
calling disable, and <B>false</B> otherwise.</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
-not NULL, task’s <B>OnDisable</B> method is invoked. <B>OnDisable</B>
-is invoked only if task was enabled. Calling <B>disable</B> 3 times
-for instance will invoke <B>OnDisable</B> only once.</P>
+not NULL, task’s <B>OnDisable</B> method is invoked <B>immediately</B>.
+<B>OnDisable</B> is invoked only if task was in enabled state.
+Calling <B>disable</B> 3 times for instance will invoke <B>OnDisable</B>
+only once.</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>void set(unsigned
@@ -536,17 +612,18 @@ long aInterval, long aIterations, void (*aCallback)() , bool
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Allows
-dynamic control of task execution parameters in one function call.
+dynamic control of task execution parameters in one method call.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note</B><B>:
</B>OnEnable and OnDisable parameters can be omitted. In that case
-they will be assigned to NULL and not called.
+they will be assigned to NULL and respective methods will no longer
+be called.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in">Next five “setter”
-functions allow changes of individual task execution control
-parameters.
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+Next five “setter” methods allow changes of individual task
+execution control parameters.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void
setInterval (unsigned long aInterval) </B>
@@ -567,9 +644,9 @@ setOnDisable (void (*aCallback)()) </B>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Next
execution time calculation takes place <B>after</B> the callback
-function is called, so new interval will be used immediately by the
+method is called, so new interval will be used immediately by the
scheduler. For the situations when one task is changing the interval
-parameter for the other, <B>setInterval</B> function calls <B>delay
+parameter for the other, <B>setInterval</B> method calls <B>delay
</B>explicitly to guarantee schedule change, however it <B>does not
</B>enable the task if task is disabled.</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Tasks that
@@ -601,6 +678,18 @@ aStatusRequest</B> should be “activated” by calling <B>setWaiting()
</B>method before making a task wait on it. Otherwise, the task will
execute immediately.
</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">The
+sequence of events to use Status Request object is as follows:</P>
+<OL>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">Create a status
+ request object</P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">Activate status
+ request object (calling its <B>setWaiting</B>() method)</P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">Set up tasks to
+ wait of the event completion</P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in">Signal completion
+ of event(s)</P>
+</OL>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
@@ -670,6 +759,38 @@ currently set control point for this task.</P>
<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
<BR>
</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><B>LOCAL TASK STORAGE
+METHODS:</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>void setLtsPointer(void *aPtr);</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
+compiled with support for LTS, this method will set the task's local
+storage pointer.</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<B>void *getLtsPointer();</B></P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If
+compiled with support for LTS, this method will return reference to
+the task's local storage.</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
+</B>the value returned has type (void *), and needs to be re-cast
+into appropriate pointer type. Please refer to example sketches for
+implementation options.
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; 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">
<BR>
</P>
@@ -703,7 +824,7 @@ constructor, so don't need to be explicitly called after creation.</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note:
</B>be default (if compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT>
enabled) scheduler is allowed to put processor to IDLE sleep mode. If
-this behavior was changed via <B>allowSleep() </B>function, <B>inti()
+this behavior was changed via <B>allowSleep()</B> method, <B>inti()
</B>will <B>NOT</B> reset allow sleep particular parameter.
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void
@@ -742,7 +863,7 @@ scheduling pass by deleting it, since it is not even considered for
execution.
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">An
-example of proper use of this function would be running some sort of
+example of proper use of this method would be running some sort of
<B>initialize</B> task in the chain, and then deleting it from the
chain since it only needs to run once.
</P>
@@ -771,20 +892,39 @@ and disables (respectively) all tasks in the chain. Convenient if
your need to enable/disable majority of the tasks (i.e. disable all
and then enable one).
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>Task&amp;
-currentTask()<BR></B><BR>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<BR><B>Task&amp; currentTask()<BR></B><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
+reference to the task, currently executing via <B>execute()</B> loop
+<B>OR </B>for OnEnable and OnDisable methods, reference to the task
+being enabled or disabled.
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">This
+distinction is important because one task can activate the other, and
+OnEnable should be referring to the task being enabled, not being
+executed.
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Could
+be used by callback methods to identify which Task actually invoked
+this callback method.</P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid">
+<B>void* currentLts()<BR></B><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns
-reference to the task, currently executing via <B>execute()</B> loop.
-Could be used by callback functions to identify which of the Tasks
-invoked callback function.</P>
+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>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Executes
-one scheduling pass, including end-of-pass sleep. This function
-typically placed inside the <B>loop()</B> function of the sketch.
-Since <B>execute</B> exits after every pass, you can put additional
+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>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
@@ -929,7 +1069,7 @@ to run once for every time the pump is turned on:</P>
&amp;waterOffCallback);</FONT><BR><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in">Example of the callback
-function:</P>
+method:</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
@@ -962,18 +1102,19 @@ met. </FONT>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"> </FONT><FONT FACE="Courier New, monospace">setup()</FONT></P>
-<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace">
- ...</FONT></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT SIZE=2><FONT FACE="Times New Roman, serif"> void
+</FONT><FONT FACE="Courier New, monospace">setup()</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>
+ ...</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
-<FONT FACE="Courier New, monospace">tWater.setIterations(parameters.retries);<BR>
+<FONT SIZE=2><FONT FACE="Courier New, monospace">tWater.setIterations(parameters.retries);<BR>
tWaterOff.setInterval(parameters.watertime * SECOND);<BR><BR><BR>
taskManager.init();<BR> taskManager.addTask(tMeasure);<BR>
taskManager.addTask(tDisplay);<BR> taskManager.addTask(tWater);<BR>
taskManager.addTask(tWaterOff);<BR> <BR> tMeasure.enable();<BR>
tDisplay.enable();<BR><BR> currentHumidity =
measureHumidity();<BR>}<BR><BR><BR>void loop ()<BR>{<BR>
-taskManager.execute();<BR>}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT><BR>
+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”
@@ -982,18 +1123,19 @@ taskManager.execute();<BR>}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Define
-“states” as callback function or functions. Each callback
-function executes activities specific to a “state” and then
-“transitions” to the next state by assigning next callback
-function to the task. </FONT>
+“states” as callback method or methods. Each callback method
+executes activities specific to a “state” and then “transitions”
+to the next state by assigning next callback method to the task. </FONT>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Transition
from one state to the next is achieved by setting next callback
-function at the end of preceding one. </FONT>
+method at the end of preceding one. </FONT>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Note:
-</B>do not call the next callback function. Let the schedule take
-care of that during the next pass. (Thus letting other tasks run). </FONT>
+</B>do not call the next callback method explicitly. Yield to the
+scheduler, and let the scheduler take care of next iteration during
+the next pass. (Thus giving other tasks change to run their callback
+methods). </FONT>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
@@ -1001,39 +1143,35 @@ care of that during the next pass. (Thus letting other tasks run). </FONT>
Blinking LED 2 times a second could be achieved this way</FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">Task
-tLedBlinker (500, -1, &amp;ledOnCallback);</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">Scheduler
-taskManager;</FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Scheduler
+ts;</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task
+tLedBlinker (500, -1, &amp;ledOnCallback, &amp;ts, true);</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">void
- ledOnCallback() {</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> turnLedOn();</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.setCallback(&amp;ledOffCallback);</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
+ ledOnCallback() {</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> turnLedOn();</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tLedBlinker.setCallback(&amp;ledOffCallback);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">void
- ledOffCallback() {</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> turnLedOff();</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.setCallback(&amp;ledOnCallback);</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
+ ledOffCallback() {</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> turnLedOff();</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tLedBlinker.setCallback(&amp;ledOnCallback);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">setup()
-{</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> taskManager.init();<BR>
- taskManager.addTask(tLedBlinker);</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> </FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.enable();</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>setup()
+{</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">loop
-() {</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> taskManager.execute();</FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT><BR>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>loop
+() {</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> ts.execute();</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT><FONT FACE="Times New Roman, serif"><BR></FONT><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Obviously
the example is simple, but gives the idea of how the tasks could be
@@ -1051,17 +1189,17 @@ used to go through states.</FONT></P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">There
-may be a need to select an option for callback function based on
+may be a need to select an option for callback method based on
certain criteria, or randomly. </FONT>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">You
-can achieve that by defining an array of callback function pointers
-and selecting one based on the criteria you need. </FONT>
+can achieve that by defining an array of callback method pointers and
+selecting one based on the criteria you need. </FONT>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Example:
when a robot detects an obstacle, it may go left, right backwards,
etc. Each of the “directions” or “behaviors” are represented
-by a different callback function. </FONT>
+by a different callback methods. </FONT>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
@@ -1084,7 +1222,7 @@ this case, define a tasks with two callbacks:</FONT></P>
do your initializationstuff here</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> </FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
-finally assigne the main callback function </FONT></FONT>
+finally assigne the main callback method </FONT></FONT>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.setCallback(&amp;workCallback);</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
@@ -1093,7 +1231,7 @@ finally assigne the main callback function </FONT></FONT>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
workCallback() {</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
-main callback function</FONT></FONT></P>
+main callback method</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> …</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
@@ -1112,7 +1250,7 @@ after initialization first pass, change the above code like this:</FONT></P>
do your initializationstuff here</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> </FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> //
-finally assigne the main callback function </FONT></FONT>
+finally assigne the main callback method </FONT></FONT>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.setCallback(&amp;workCallback);</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.enable();</FONT></FONT></P>
@@ -1136,7 +1274,7 @@ pass. </FONT>
<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">In
case of interrupt-driven program flow, tasks could be scheduled to
run once to request asynchronous execution (request), and then
-re-enabled (restarted) again with a different callback function to
+re-enabled (restarted) again with a different callback method to
process the results. </FONT>
</P>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
@@ -1311,7 +1449,7 @@ Task should be enabled</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
-tBlink does not really need a callback function</FONT></FONT></P>
+tBlink does not really need a callback method</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
since it just waits for 5 seconds for the first </FONT></FONT>
</P>
@@ -1769,13 +1907,11 @@ StatusRequest Sensor Emulation Test. Complex Test.&quot;); </FONT></FONT>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void
loop() {</FONT></FONT></P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
-</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">
<FONT FACE="Courier New, monospace"><FONT SIZE=2>ts.execute();</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
-<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
</P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
@@ -1783,6 +1919,121 @@ 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>
+ </P>
+</OL>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><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
+represents variables specific for a particular task. This may be
+needed if you plan to use same callback method for multiple tasks.</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 you have several sensors of the same type. The
+actual process of triggering measurement and collecting information
+is identical. The only difference is the sensor address and a
+variable for storing the results. </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">In
+this case each of the tasks, which performs measurement will utilize
+the same callback methods. The only difference will be the variables
+(specific for each of the sensor). </FONT></FONT>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">Let's
+define a sensor data structure and declare a couple of variables (for
+2 sensors for instance)</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>typedef struct {</FONT></FONT></P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<FONT FACE="Courier New, monospace"><FONT SIZE=2> unsigned int
+ address;</FONT></FONT></P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<FONT FACE="Courier New, monospace"><FONT SIZE=2> unsigned
+long distance;</FONT></FONT></P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>} sensor_data;</FONT></FONT></P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<BR>
+</P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>sensor_data s1, s2; </FONT></FONT>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">Two
+separate tasks are running to collect sensor data.</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">(Note
+that both tasks refer to the same callback methods)</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR>
+</P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>Scheduler ts;</FONT></FONT></P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>Task t1(100, -1,
+&amp;Measure, &amp;ts, false, &amp;MeasureOn); </FONT></FONT>
+</P>
+<P LANG="" CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in">
+<FONT FACE="Courier New, monospace"><FONT SIZE=2>Task t2(100, -1,
+&amp;Measure, &amp;ts, false, &amp;MeasureOn); </FONT></FONT>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><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">Assign
+pointers to the respective variables in the <B>setup</B>() method:</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>void
+setup() {</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 1.48in; margin-bottom: 0in">…</P>
+<P CLASS="western" STYLE="margin-left: 1.48in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>t1.setLtsPointer(&amp;s1);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 1.48in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>t2.setLtsPointer(&amp;s2);</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 1.48in; 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>}</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><FONT SIZE=2 STYLE="font-size: 11pt">Obtain
+reference to specific <B>sensor_data</B> structure inside the common
+callback method:</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>void
+Measure() {</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> Task&amp;
+T = ts.currentTask(); </FONT></FONT>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> Sensor_data&amp;
+V = *((sensor_data*) T.getLtsPointer());</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
+For t1, V will be pointing at s1</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>//
+For t2, V will be pointing at s2</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>//
+Alternatively use the Scheduler method:</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> Sensor_data&amp;
+V1 = *((sensor_data*) ts.currentLts());</FONT></FONT></P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><BR>
+</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; text-indent: 0.49in; margin-bottom: 0in">
+…</P>
+<P CLASS="western" STYLE="margin-left: 0.98in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> V.distance
+= &lt;calculate your values here&gt;;</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.98in; margin-bottom: 0in"><BR>
+</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>
@@ -1796,9 +2047,9 @@ information and implementation options.</FONT></FONT></P>
<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Real
time examples of TaskScheduler are available here:</FONT></FONT></P>
<OL>
- <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/">http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/</A></U></FONT></FONT></FONT></P>
- <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/">http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/</A></U></FONT></FONT></FONT></P>
- <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider">http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider</A></U></FONT></FONT></FONT></P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/"><FONT FACE="Courier New, monospace"><FONT SIZE=2>http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/</FONT></FONT></A></U></FONT></P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/"><FONT FACE="Courier New, monospace"><FONT SIZE=2>http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/</FONT></FONT></A></U></FONT></P>
+ <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT COLOR="#0000ff"><U><A HREF="http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider"><FONT FACE="Courier New, monospace"><FONT SIZE=2>http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider</FONT></FONT></A></U></FONT></P>
</OL>
<P CLASS="western" STYLE="margin-bottom: 0in"><BR>
</P>
diff --git a/keywords.txt b/keywords.txt
index 1afc041..6bbbc3a 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -20,6 +20,7 @@ deleteTask KEYWORD2
disableAll KEYWORD2
enableAll KEYWORD2
currentTask KEYWORD2
+currentLts KEYWORD2
execute KEYWORD2
allowSleep KEYWORD2
enable KEYWORD2
@@ -56,6 +57,8 @@ setId KEYWORD2
getId KEYWORD2
setControlPoint KEYWORD2
getControlPoint KEYWORD2
+setLtsPointer KEYWORD2
+getLtsPointer KEYWORD2
#######################################
# Constants (LITERAL1)
diff --git a/library.properties b/library.properties
index 1eda34c..d347938 100644
--- a/library.properties
+++ b/library.properties
@@ -1,9 +1,9 @@
name=TaskScheduler
-version=1.8.1
+version=1.8.2
author=Anatoli Arkhipenko <arkhipenko@hotmail.com>
maintainer=Anatoli Arkhipenko <arkhipenko@hotmail.com>
sentence=A light-weight cooperative multitasking library for arduino microcontrollers.
-paragraph=Enables developers to achieve pseudo multi-tasking. The library is NOT pre-emptive, and as such requires cooperative programming to be used; does NOT use any of the timers therefore does not affect PWM pins. Includes support for status request objects, allowing tasks to wait on and signal event completion between each other.
-category=Schedulers
+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)
+category=Timing
url=https://github.com/arkhipenko/TaskScheduler.git
architectures=*
diff --git a/src/TaskScheduler.h b/src/TaskScheduler.h
index 634852f..b1f3ca0 100644
--- a/src/TaskScheduler.h
+++ b/src/TaskScheduler.h
@@ -1,23 +1,23 @@
-// Cooperative multitasking library for Arduino version 1.8.1
+// Cooperative multitasking library for Arduino version 1.8.2
// Copyright (c) 2015 Anatoli Arkhipenko
//
// Changelog:
// v1.0.0:
// 2015-02-24 - Initial release
-// 2015-02-28 - added delay() and disableOnLastIteration() functions
-// 2015-03-25 - changed scheduler execute() function for a more precise delay calculation:
+// 2015-02-28 - added delay() and disableOnLastIteration() methods
+// 2015-03-25 - changed scheduler execute() method for a more precise delay calculation:
// 1. Do not delay if any of the tasks ran (making request for immediate execution redundant)
// 2. Delay is invoked only if none of the tasks ran
-// 3. Delay is based on the min anticipated wait until next task _AND_ the runtime of execute function itself.
-// 2015-05-11 - added restart() and restartDelayed() functions to restart tasks which are on hold after running all iterations
+// 3. Delay is based on the min anticipated wait until next task _AND_ the runtime of execute method itself.
+// 2015-05-11 - added restart() and restartDelayed() methods to restart tasks which are on hold after running all iterations
// 2015-05-19 - completely removed delay from the scheduler since there are no power saving there. using 1 ms sleep instead
//
// v1.4.1:
-// 2015-09-15 - more careful placement of AVR-specific includes for sleep functions (compatibility with DUE)
+// 2015-09-15 - more careful placement of AVR-specific includes for sleep method (compatibility with DUE)
// sleep on idle run is no longer a default and should be explicitly compiled with _TASK_SLEEP_ON_IDLE_RUN defined
//
// v1.5.0:
-// 2015-09-20 - access to currently executing task (for callback functions)
+// 2015-09-20 - access to currently executing task (for callback methods)
// 2015-09-20 - pass scheduler as a parameter to the task constructor to append the task to the end of the chain
// 2015-09-20 - option to create a task already enabled
//
@@ -32,10 +32,10 @@
// 2015-10-01 - made version numbers semver compliant (documentation only)
//
// v1.7.0:
-// 2015-10-08 - introduced callback run counter - callback functions can branch on the iteration number.
+// 2015-10-08 - introduced callback run counter - callback methods can branch on the iteration number.
// 2015-10-11 - enableIfNot() - enable a task only if it is not already enabled. Returns true if was already enabled, false if was disabled.
// 2015-10-11 - disable() returns previous enable state (true if was enabled, false if was already disabled)
-// 2015-10-11 - introduced callback functions "on enable" and "on disable". On enable runs every time enable is called, on disable runs only if task was enabled
+// 2015-10-11 - introduced callback methods "on enable" and "on disable". On enable runs every time enable is called, on disable runs only if task was enabled
// 2015-10-12 - new Task method: forceNextIteration() - makes next iteration happen immediately during the next pass regardless how much time is left
//
// v1.8.0:
@@ -44,6 +44,13 @@
//
// v1.8.1:
// 2015-10-22 - implement Task id and control points to support identification of failure points for watchdog timer logging
+//
+// v1.8.2:
+// 2015-10-27 - implement Local Task Storage Pointer (allow use of same callback code for different tasks)
+// 2015-10-27 - bug: currentTask() method returns incorrect Task reference if called within OnEnable and OnDisable methods
+// 2015-10-27 - protection against infinite loop in OnEnable (if enable() methods are called within OnEnable)
+// 2015-10-29 - new currentLts() method in the scheduler class returns current task's LTS pointer in one call
+
/* ============================================
Cooperative multitasking library code is placed under the MIT license
@@ -80,10 +87,11 @@ THE SOFTWARE.
* The following "defines" control library functionality at compile time,
* and should be used in the main sketch depending on the functionality required
*
- * #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
- * #define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between tasks if no callback functions were invoked during the pass
- * #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 of wdt control points and task ids
+ * #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
+ * #define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between tasks if no callback methods were invoked during the pass
+ * #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
*/
#ifdef _TASK_SLEEP_ON_IDLE_RUN
@@ -104,34 +112,13 @@ class StatusRequest {
inline int getStatus() { return iStatus; }
private:
- unsigned int iCount;
+ unsigned int iCount; // waiting for more that 65000 events seems unreasonable: unsigned int should be sufficient
int iStatus; // negative = error; zero = OK; >positive = OK with a specific status
};
#endif
-class Task;
-
-class Scheduler {
- public:
- Scheduler();
- inline void init() { iFirst = NULL; iLast = NULL; iCurrent = NULL; }
- void addTask(Task& aTask);
- void deleteTask(Task& aTask);
- void disableAll();
- void enableAll();
- void execute();
- inline Task& currentTask() {return *iCurrent; }
-#ifdef _TASK_SLEEP_ON_IDLE_RUN
- void allowSleep(bool aState = true) { iAllowSleep = aState; }
-#endif
-
- private:
- Task *iFirst, *iLast, *iCurrent;
-#ifdef _TASK_SLEEP_ON_IDLE_RUN
- bool iAllowSleep;
-#endif
-};
+class Scheduler;
class Task {
friend class Scheduler;
@@ -174,12 +161,16 @@ class Task {
inline void setControlPoint(unsigned int aPoint) { iControlPoint = aPoint; }
inline unsigned int getControlPoint() { return iControlPoint; }
#endif
-
+#ifdef _TASK_LTS_POINTER
+ inline void setLtsPointer(void *aPtr) { iLTS = aPtr; }
+ inline void* getLtsPointer() { return iLTS; }
+#endif
private:
void reset();
volatile bool iEnabled;
+ bool iInOnEnable;
volatile unsigned long iInterval;
volatile unsigned long iPreviousMillis;
#ifdef _TASK_TIMECRITICAL
@@ -200,6 +191,34 @@ class Task {
unsigned int iTaskID;
unsigned int iControlPoint;
#endif
+#ifdef _TASK_LTS_POINTER
+ void *iLTS;
+#endif
+};
+
+class Scheduler {
+ friend class Task;
+ public:
+ Scheduler();
+ inline void init() { iFirst = NULL; iLast = NULL; iCurrent = NULL; }
+ void addTask(Task& aTask);
+ void deleteTask(Task& aTask);
+ void disableAll();
+ void enableAll();
+ void execute();
+ inline Task& currentTask() {return *iCurrent; }
+#ifdef _TASK_SLEEP_ON_IDLE_RUN
+ void allowSleep(bool aState = true) { iAllowSleep = aState; }
+#endif
+#ifdef _TASK_LTS_POINTER
+ inline void* currentLts() {return iCurrent->iLTS; }
+#endif
+
+ private:
+ Task *iFirst, *iLast, *iCurrent;
+#ifdef _TASK_SLEEP_ON_IDLE_RUN
+ bool iAllowSleep;
+#endif
};
@@ -214,13 +233,13 @@ Task::Task( unsigned long aInterval, long aIterations, void (*aCallback)(), Sche
reset();
set(aInterval, aIterations, aCallback, aOnEnable, aOnDisable);
if (aScheduler) aScheduler->addTask(*this);
- if (aEnable) enable();
#ifdef _TASK_STATUS_REQUEST
iStatusRequest = NULL;
#endif
#ifdef _TASK_WDT_IDS
iTaskID = ++__task_id_counter;
#endif
+ if (aEnable) enable();
}
@@ -278,7 +297,7 @@ void Task::waitFor(StatusRequest* aStatusRequest) {
* out of the execution chain as a result
*/
void Task::reset() {
- iEnabled = false;
+ iEnabled = iInOnEnable = false;
iPreviousMillis = 0;
iPrev = NULL;
iNext = NULL;
@@ -290,14 +309,17 @@ void Task::reset() {
#ifdef _TASK_WDT_IDS
iControlPoint = 0;
#endif
+#ifdef _TASK_LTS_POINTER
+ iLTS = NULL;
+#endif
}
/** Explicitly set Task execution parameters
* @param aInterval - execution interval in ms
* @param aIterations - number of iterations, use -1 for no limit
- * @param aCallback - pointer to the callback function which executes the task actions
- * @param aOnEnable - pointer to the callback function which is called on enable()
- * @param aOnDisable - pointer to the callback function which is called on disable()
+ * @param aCallback - pointer to the callback method which executes the task actions
+ * @param aOnEnable - pointer to the callback method which is called on enable()
+ * @param aOnDisable - pointer to the callback method which is called on disable()
*/
void Task::set(unsigned long aInterval, long aIterations, void (*aCallback)(),bool (*aOnEnable)(), void (*aOnDisable)()) {
iInterval = aInterval;
@@ -320,9 +342,21 @@ void Task::setIterations(long aIterations) {
* and resets the RunCounter back to zero
*/
void Task::enable() {
- iRunCounter = 0;
- iPreviousMillis = millis() - iInterval;
- iEnabled = iOnEnable ? (*iOnEnable)() : true;
+ if (iScheduler) { // activation without active scheduler does not make sense
+ iRunCounter = 0;
+ iPreviousMillis = millis() - iInterval;
+ if (iOnEnable && !iInOnEnable) {
+ Task *current = iScheduler->iCurrent;
+ iScheduler->iCurrent = this;
+ iInOnEnable = true; // Protection against potential infinite loop
+ iEnabled = (*iOnEnable)();
+ iInOnEnable = false; // Protection against potential infinite loop
+ iScheduler->iCurrent = current;
+ }
+ else {
+ iEnabled = true;
+ }
+ }
}
/** Enables the task only if it was not enabled already
@@ -375,8 +409,13 @@ void Task::setInterval (unsigned long aInterval) {
*/
bool Task::disable() {
bool previousEnabled = iEnabled;
- iEnabled = false;
- if (previousEnabled && iOnDisable) (*iOnDisable)();
+ iEnabled = iInOnEnable = false;
+ if (previousEnabled && iOnDisable) {
+ Task *current = iScheduler->iCurrent;
+ iScheduler->iCurrent = this;
+ (*iOnDisable)();
+ iScheduler->iCurrent = current;
+ }
return (previousEnabled);
}