From bb20df9c654cbed77bb5007814ae06f20f08ec36 Mon Sep 17 00:00:00 2001
From: Anatoli Arkhipenko Task Scheduler –
cooperative multitasking for Arduino microcontrollers Version 1.7.0:
-2015-10-12 Version 1.8.0:
+2015-10-15 OVERVIEW:
Power saving via entering IDLE sleep mode between tasks are scheduled to run
+Support for task + invocation via Status Request object
Execution interval
+Execution event + (Status Request)
Number of execution iterations
Piece of code @@ -104,7 +108,7 @@ tasks in the chain always requires immediate execution (aInterval =
Below is the flowchart of a Task lifecycle:
-

Note: Task @@ -124,6 +128,28 @@ to run in a truly periodical manner (in absolute time terms).
In addition to +time-only invocation, tasks can be scheduled to wait on an event +employing StatusRequest objects (more about Status Requests later).
+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” +completion of its function via Status Request object. Tasks t2 and t3 +are “waiting” on the same Status Request object. As soon as +status request completes, t2 and t3 are activated.
+
+
Alternative scenario is +the ne task (t1) and waiting for the completion of a number of tasks +(t2, t3). When done, t2 and t3 signal completion of their functions, +t1 is invoked. +
+
+
Please see the examples +at the end of this document.
+
+
COMPILE PARAMETERS:
This library could be compiled with several options. @@ -163,6 +189,15 @@ conserve power. Device in SLEEP_MODE_IDLE wakes up to all hardware and timer interrupts, so scheduling is kept current.
#define +_TASK_STATUS_REQUEST
+…will compile +TaskScheduler with support for StatusRequest object. Status Requests +are objects allowing tasks to wait on an event, and signal event +completion to each other. +
++
NOTE: above parameters are DISABLED by default, and need to be explicitly enabled.
@@ -175,7 +210,8 @@ enabled.API DOCUMENTATION:
TASKS:
++TASKS:
CREATION:
@@ -197,7 +233,7 @@ tasks are created disabled by default.Task(unsigned long aInterval, long aIterations, void (*aCallback)(), Scheduler* aScheduler, bool aEnable, bool -(*aOnEnable)(), void (*aOnDisable)(),);
+(*aOnEnable)(), void (*aOnDisable)())
Constructor @@ -249,6 +285,18 @@ task is scheduled for execution immediately. Enable tasks with delay to defer first run of the task.
+Task(void (*aCallback)(), Scheduler* aScheduler, bool +(*aOnEnable)(), void (*aOnDisable)())
+
+
If +compiled with support for Status Request objects, this constructor +creates a Task for activation on event (since such tasks must run +waitFor() method, their interval, iteration and +enabled status will be set by that method.
+
+
INFORMATION
The following 3 “getter” functions return task status @@ -329,7 +377,8 @@ current pass is the last iteration.
CONTROL:
-
+
+
void enable();
@@ -496,16 +545,49 @@ ran through all their allocated iterations are disabled.
+void waitFor(StatusRequest* aStatusRequest);
+
+
+
If +compiled with support for Status Requests, this method makes task +wait for the completion of aStatusRequest event. +
+waitFor() +sets tasks interval to 0 (zero) for immediate execution +when event happens, and also sets the number of iterations to 1.
+Note: +aStatusRequest should be “activated” by calling setWaiting() +method before making a task wait on it. Otherwise, the task will +execute immediately. +
TASK SCHEDULER:
+StatusRequest* +getStatusRequest()
+Returns +a StatusReqeust object this Task was waiting on. +
+
+
+
+
CREATION:
++TASK SCHEDULER:
+CREATION:
+
+
+
Scheduler()
Default @@ -614,6 +696,97 @@ statements after execute inside the loop()
+
+STATUS REQUEST:
+
+
+
+CREATION:
+
+
+
StatusRequest()
+
Default +constructor. +
+Takes +no parameters. Creates Status Request object, which is assigned a +status of “completed” on creation. +
+
+
void +setWaiting(unsigned int aCount)
+Activates +Status Request object. By default each object is set to wait on one +event only, however, if aCount is supplied, Status Request can +wait on multiple events. For instance, setWaiting(3) will wait +on three signals. An example could be waiting for completion of +measurements from 3 sensors. +
+
+
bool signal(int +aStatus)
+Signals +completion of the event to the Status Request object, and passes a +completion code, which could be interrogated later. +
+Note: + passing a negative 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. +
+Note: +only the latest status code is kept.
+
+
bool signalComplete +(int aStatus)
+Signals +completion of ALL 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. +
+
+
bool pending() +
+Returns +true if status request is still waiting for event or events to +happen.
+
+
bool completed () +
+Returns +true if status has completed.
+
+
int getStatus()
+Returns +the status code passed to the status request object by the signal() +and signalComplete() methods. +
+Any +positive number is considered a successful completion status.
+A +0 (zero) is considered a default successful completion status.
+Any +negative number is considered an error code and unsuccessful +completion of a request.
+
+
+
+
IMPLEMENTATION SCENARIOS AND IDEAS:
@@ -971,12 +1144,26 @@ is the implementation using TaskScheduler
#include
-<TaskScheduler.h>
#define LEDPIN 13
Scheduler
-ts;
+
+
#define +_TASK_SLEEP_ON_IDLE_RUN
+#include +<TaskScheduler.h>
+
+
#define + LEDPIN 13
+
+
+
Scheduler +ts;
+
Task -tWrapper(30000L, -1, &WrapperCallback, &ts, true);
+tWrapper(30000, -1, &WrapperCallback, &ts, true);Task tBlink(5000, 1, NULL, &ts, false, &BlinkOnEnable, &BlinkOnDisable);
@@ -986,12 +1173,16 @@ tLED(0, -1, NULL, &ts, false, NULL, &LEDOff);void WrapperCallback() {
- tBlink.restartDelayed();
+
+Serial.println("In
+WrapperCallback");
+tBlink.restartDelayed();
// LED blinking is initiated
- //every 30
-seconds for 5 seconds
}
bool BlinkOnEnable() {
- tLED.setInterval(
+
+Serial.println("In
+BlinkOnEnable");
+tLED.setInterval(
500 + random(501) ); tLED.setCallback(
+
+tLED.setCallback(
&LEDOn); tLED.enable();
+tLED.enable(); return
-true; // Task should be enabled
+return true; //
+Task should be enabled }
void BlinkOnDisable() {
-tLED.disable();
++Serial.println("In +BlinkOnDisable");
++tLED.disable();
}
void LEDOn () {
- digitalWrite(LEDPIN,
+
+Serial.println("In
+LEDOn");
+digitalWrite(LEDPIN,
HIGH); tLED.setCallback(
+
+tLED.setCallback(
&LEDOff); } void
LEDOff () { digitalWrite(LEDPIN,
+
+Serial.println("In
+LEDOff");
+digitalWrite(LEDPIN,
LOW); tLED.setCallback(
+
+tLED.setCallback(
&LEDOn); } void
-setup() {
+Serial.begin(115200);
+
+
+pinMode(LEDPIN,
+OUTPUT);
+ } void
+loop() {
+// put your main
+code here, to run repeatedly:
+ts.execute(); } USING
+ STATUS REQUEST OBJECTS
+ This
+test emulates querying 3 sensors once every 10 seconds, each could
+respond with a different delay (ultrasonic sensors for instance) and
+printing a min value of the three when all three have reported their
+values. The
+overall timeout of 1 second is setup as well. An
+error message needs to be printed if a timeout occurred instead of a
+value.
+ #define
+_TASK_SLEEP_ON_IDLE_RUN #define
+_TASK_STATUS_REQUEST #include
+<TaskScheduler.h> StatusRequest
+measure; Scheduler
+ts;
+ Task
+tCycle(10000, -1, &CycleCallback, &ts, true); Task
+tMeasure(1000, 1, &MeasureCallback, &ts, false,
+&MeasureEnable, &MeasureDisable); Task
+tCalculate(&CalcCallback, &ts); Task
+tSensor1(0, 1, &S1Callback, &ts, false, &S1Enable); Task
+tSensor2(0, 1, &S2Callback, &ts, false, &S2Enable); Task
+tSensor3(0, 1, &S3Callback, &ts, false, &S3Enable); long
+distance, d1, d2, d3; void
+CycleCallback() {
+Serial.println("CycleCallback:
+Initiating measurement cycle every 10 seconds");
+tMeasure.restartDelayed(); } bool
+MeasureEnable() {
+Serial.println("MeasureEnable:
+Activating sensors");
+
+distance = 0;
+measure.setWaiting(3);
+// Set the StatusRequest to wait for 3 signals.
+
+tCalculate.waitFor(&measure);
+tSensor1.restart();
+tSensor2.restart();
+tSensor3.restart();
+return true; } void
+MeasureCallback() {
+Serial.println("MeasureCallback:
+Invoked by calculate task or one second later");
+
+if
+(measure.pending()) {
+ tCalculate.disable();
+ measure.signalComplete(-1);
+ // signal error
+ Serial.println("MeasureCallback:
+Timeout!");
+}
+else {
+ Serial.print("MeasureCallback:
+Min distance=");Serial.println(distance);
+} } void
+MeasureDisable() {
+Serial.println("MeasureDisable:
+Cleaning up");
+
+
+tSensor1.disable();
+tSensor2.disable();
+tSensor3.disable(); } void
+CalcCallback() {
+Serial.println("CalcCallback:
+calculating");
+
+distance = -1;
+if (
+measure.getStatus() >= 0) { // only calculate if statusrequest
+ended successfully
+ distance = d1 <
+d2 ? d1 : d2;
+ distance = d3 <
+distance ? d3 : distance;
+ tMeasure.forceNextIteration();
+} } /**
+Simulation code for sensor 1 *
+ ----------------------------
+*/ bool
+S1Enable() {
+Serial.print("S1Enable:
+Triggering sensor1. Delay=");
+
+tSensor1.setInterval(
+random(1200) ); // Simulating sensor delay, which could go over 1
+second and cause timeout
+d1 = 0;
+
+Serial.println(
+tSensor1.getInterval() );
+return true; } void
+S1Callback() {
+Serial.print("S1Callback:
+Emulating measurement. d1=");
+
+d1 = random(501); //
+pick a value from 0 to 500 "centimeters" simulating a
+measurement
+
+measure.signal();
+
+Serial.println(d1);
+ } /**
+Simulation code for sensor 2 *
+ ----------------------------
+*/ bool
+S2Enable() {
+Serial.print("S2Enable:
+Triggering sensor2. Delay=");
+
+tSensor2.setInterval(
+random(1200) ); // Simulating sensor delay, which could go over 1
+second and cause timeout
+d2 = 0;
+Serial.println(
+tSensor2.getInterval() );
+return true; } void
+S2Callback() {
+Serial.print("S2Callback:
+Emulating measurement. d2=");
+
+d2 = random(501); //
+pick a value from 0 to 500 "centimeters" simulating a
+measurement
+measure.signal();
+Serial.println(d2);
+
+ } /**
+Simulation code for sensor 3 *
+ ----------------------------
+*/ bool
+S3Enable() {
+Serial.print("S3Enable:
+Triggering sensor3. Delay=");
+
+tSensor3.setInterval(
+random(1200) ); // Simulating sensor delay, which could go over 1
+second and cause timeout
+d3 = 0;
+Serial.println(
+tSensor3.getInterval() );
+return true; } void
+S3Callback() {
+Serial.print("S3Callback:
+Emulating measurement. d3=");
+
+d3 = random(501); //
+pick a value from 0 to 500 "centimeters" simulating a
+measurement
+measure.signal();
+
+Serial.println(d3);
+ } /**
+Main Arduino code *
+ Not much is left here - everything is taken care of by the framework
+*/ void
+setup() {
+Serial.begin(115200);
+Serial.println("TaskScheduler
+StatusRequest Sensor Emulation Test. Complex Test.");
+
+randomSeed(analogRead(A1)+millis()); } void
+loop() {
+
+ts.execute(); }
@@ -1064,12 +1276,412 @@ task finishes (or disabled ahead of time)
// put your setup code here, to run once:
}
void
-loop() {
// put your main code here, to run repeatedly:
-ts.execute();
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+