update Code

This commit is contained in:
Siwat Sirichai 2019-08-09 09:17:05 +07:00
parent 3c47103b39
commit a641fad56c
119 changed files with 10997 additions and 5 deletions

View file

@ -0,0 +1,84 @@
/**
* TaskScheduler Test
*
* Initially only tasks 1 and 2 are enabled
* Task1 runs every 2 seconds 10 times and then stops
* Task2 runs every 3 seconds indefinitely
* Task1 enables Task3 at its first run
* Task3 run every 5 seconds
* Task1 disables Task3 on its last iteration and changed Task2 to run every 1/2 seconds
* At the end Task2 is the only task running every 1/2 seconds
*/
#include <TaskScheduler.h>
// Callback methods prototypes
void t1Callback();
void t2Callback();
void t3Callback();
//Tasks
Task t4();
Task t1(2000, 10, &t1Callback);
Task t2(3000, TASK_FOREVER, &t2Callback);
Task t3(5000, TASK_FOREVER, &t3Callback);
Scheduler runner;
void t1Callback() {
Serial.print("t1: ");
Serial.println(millis());
if (t1.isFirstIteration()) {
runner.addTask(t3);
t3.enable();
Serial.println("t1: enabled t3 and added to the chain");
}
if (t1.isLastIteration()) {
t3.disable();
runner.deleteTask(t3);
t2.setInterval(500);
Serial.println("t1: disable t3 and delete it from the chain. t2 interval set to 500");
}
}
void t2Callback() {
Serial.print("t2: ");
Serial.println(millis());
}
void t3Callback() {
Serial.print("t3: ");
Serial.println(millis());
}
void setup () {
Serial.begin(115200);
Serial.println("Scheduler TEST");
runner.init();
Serial.println("Initialized scheduler");
runner.addTask(t1);
Serial.println("added t1");
runner.addTask(t2);
Serial.println("added t2");
delay(5000);
t1.enable();
Serial.println("Enabled t1");
t2.enable();
Serial.println("Enabled t2");
}
void loop () {
runner.execute();
}

View file

@ -0,0 +1,78 @@
#define _TASK_SLEEP_ON_IDLE_RUN
#include <TaskScheduler.h>
Scheduler runner;
// Callback methods prototypes
void t1Callback();
void t2Callback();
void t3Callback();
// Tasks
Task t4();
Task t1(2000, 10, &t1Callback, &runner, true); //adding task to the chain on creation
Task t2(3000, TASK_FOREVER, &t2Callback, &runner, true); //adding task to the chain on creation
Task t3(5000, TASK_FOREVER, &t3Callback);
// Test
// Initially only tasks 1 and 2 are enabled
// Task1 runs every 2 seconds 10 times and then stops
// Task2 runs every 3 seconds indefinitely
// Task1 enables Task3 at its first run
// Task3 run every 5 seconds
// loop() runs every 1 second (a default scheduler delay, if no shorter tasks' interval is detected)
// Task1 disables Task3 on its last iteration and changed Task2 to run every 1/2 seconds
// Because Task2 interval is shorter than Scheduler default tick, loop() executes ecery 1/2 seconds now
// At the end Task2 is the only task running every 1/2 seconds
//
// NOTE that t1 and t2 are affected by the delay() function in the setup() method and are scheduled immediately twice to "catch up" with millis().
void t1Callback() {
Serial.print("t1: ");
Serial.println(millis());
if (t1.isFirstIteration()) {
runner.addTask(t3);
t3.enable();
Serial.println("t1: enabled t3 and added to the chain");
}
if (t1.isLastIteration()) {
t3.disable();
runner.deleteTask(t3);
t2.setInterval(500);
Serial.println("t1: disable t3 and delete it from the chain. t2 interval set to 500");
}
}
void t2Callback() {
Serial.print("t2: ");
Serial.println(millis());
}
void t3Callback() {
Serial.print("t3: ");
Serial.println(millis());
}
void setup () {
Serial.begin(115200);
delay(5000);
Serial.println("Scheduler TEST");
runner.startNow(); // set point-in-time for scheduling start
}
void loop () {
runner.execute();
// Serial.println("Loop ticks at: ");
// Serial.println(millis());
}

View file

@ -0,0 +1,80 @@
/**
* TaskScheduler Test of OnEnable and OnDisable methods and illustration of using wrapper tasks for timout purposes
*
* A wrapper task runs every 10 seconds and initiates the test case
* Another task is run once for 5 seconds, and serves as a LED blinking timeout - 5 seconds
* Finally, a dedicated task which controls LED is running periodically until stopped, and makes the LED blink with 0.5 to 1 second interval.
*
*/
#define _TASK_SLEEP_ON_IDLE_RUN
#include <TaskScheduler.h>
#ifndef LED_BUILTIN
#define LED_BUILTIN 13 // define appropriate pin for your board
#endif
Scheduler ts;
// Callback methods prototypes
void WrapperCallback();
bool BlinkOnEnable();
void BlinkOnDisable();
void LEDOn();
void LEDOff();
// Tasks
Task tWrapper(10000L, TASK_FOREVER, &WrapperCallback, &ts, true);
Task tBlink(5000, TASK_ONCE, NULL, &ts, false, &BlinkOnEnable, &BlinkOnDisable);
Task tLED(0, TASK_FOREVER, NULL, &ts, false, NULL, &LEDOff);
void WrapperCallback() {
tBlink.restartDelayed(); // LED blinking is initiated
//every 30 seconds for 5 seconds
}
// Upon being enabled, tBlink will define the parameters
// and enable LED blinking task, which actually controls
// the hardware (LED in this example)
bool BlinkOnEnable() {
tLED.setInterval( 200 + random(801) );
tLED.setCallback( &LEDOn);
tLED.enable();
return true; // Task should be enabled
}
// tBlink does not really need a callback function
// since it just waits for 5 seconds for the first
// and only iteration to occur. Once the iteration
// takes place, tBlink is disabled by the Scheduler,
// thus executing its OnDisable method below.
void BlinkOnDisable() {
tLED.disable();
}
void LEDOn () {
digitalWrite(LED_BUILTIN , HIGH);
tLED.setCallback( &LEDOff);
}
void LEDOff () {
digitalWrite(LED_BUILTIN , LOW);
tLED.setCallback( &LEDOn);
}
// Note that LEDOff method serves as OnDisable method
// to make sure the LED is turned off when the tBlink
// task finishes (or disabled ahead of time)
void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN , OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
ts.execute();
}

View file

@ -0,0 +1,90 @@
/** This test demonstrates interaction between three simple tasks via StatusRequest object.
* Task T1 runs every 5 seconds and signals completion of a status request st.
* Tasks T2 and T3 are waiting on the same request (st)
* Task T3 does not renew its interest in status request st, so it is only invoked once (first iteration)
* Task T2 is invoked every time st completes, because it renews its interest in status of status request object st every iteration of T1
*/
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STATUS_REQUEST
#include <TaskScheduler.h>
StatusRequest st;
Scheduler ts;
// Callback methods prototypes
void Callback1();
void Disable1();
void Callback2();
void Callback3();
void PrepareStatus();
// Tasks
Task t1(5000, TASK_ONCE, &Callback1, &ts, true, NULL, &Disable1);
Task t2(&Callback2, &ts);
Task t3(&Callback3, &ts);
/** T1 callback
* T1 just signals completion of st every 5 seconds
*/
void Callback1() {
Serial.println("T1: Signaling completion of ST");
st.signalComplete();
}
/** T1 On Disable callback
* This callback renews the status request and restarts T1 delayed to run again in 5 seconds
*/
void Disable1() {
PrepareStatus();
t1.restartDelayed();
}
/** T2 callback
* Invoked when status request st completes
*/
void Callback2() {
Serial.println("T2: Invoked due to completion of ST");
}
/** T3 callback
* Invoked when status request st completes.
* This is only run once since T3 does not renew its interest in the status request st after first iteration
*/
void Callback3() {
Serial.println("T3: Invoked due to completion of ST");
}
/** Prepare Status request st for another iteration
*
*/
void PrepareStatus() {
st.setWaiting(); // set the statusrequest object for waiting
t2.waitFor(&st); // request tasks 1 & 2 to wait on the object st
}
/** Main Arduino code
* Not much to do here. Just init Serial and set the initial status request
*/
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("TaskScheduler: Status Request Test 1. Simple Test.");
ts.startNow();
PrepareStatus();
t3.waitFor(&st);
t1.delay();
}
void loop() {
ts.execute();
}

View file

@ -0,0 +1,181 @@
/** 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>
#ifdef ARDUINO_ARCH_STM32F1
#define A0 3
#endif
StatusRequest measure;
Scheduler ts;
// Callback methods prototypes
void CycleCallback();
void MeasureCallback();
bool MeasureEnable();
void MeasureDisable();
void CalcCallback();
void S1Callback(); bool S1Enable();
void S2Callback(); bool S2Enable();
void S3Callback(); bool S3Enable();
// Tasks
Task tCycle(10000, TASK_FOREVER, &CycleCallback, &ts, true);
Task tMeasure(1000, TASK_ONCE, &MeasureCallback, &ts, false, &MeasureEnable, &MeasureDisable);
Task tCalculate(&CalcCallback, &ts);
Task tSensor1(0, TASK_ONCE, &S1Callback, &ts, false, &S1Enable);
Task tSensor2(0, TASK_ONCE, &S2Callback, &ts, false, &S2Enable);
Task tSensor3(0, TASK_ONCE, &S3Callback, &ts, false, &S3Enable);
long distance, d1, d2, d3;
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.restartDelayed();
tSensor2.restartDelayed();
tSensor3.restartDelayed();
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.");
#ifdef ARDUINO_ARCH_STM32F1
pinMode(A0, INPUT_ANALOG);
#endif
randomSeed(analogRead(A0)+millis());
}
void loop() {
ts.execute();
}

View file

@ -0,0 +1,117 @@
/**
* This is a test to prove that processor really goes into IDLE sleep.
* For this setup:
*
*
Task c(10, -1, &Count, &ts);
Task t(10000, 1, NULL, &ts, true, &tOn, &tOff);
The result are:
1): With #define _TASK_SLEEP_ON_IDLE_RUN enabled
On Arduino Uno:
Start
c1=10771 - v2.5.0 (v1.9.0: same)
c2=1001
On Teensy 3.5 (120MHz ARM):
Start
c1=21065
c2=1001
On esp8266 (80 MHz)
Start
c1=10492
c2=1001
On STM32F103RCBT6 (Maple Mini @72 MHz)
Start
c1=21004
c2=1001
and
2): With #define _TASK_SLEEP_ON_IDLE_RUN disabled (commented out)
Arduino Uno:
Start
c1=722426 - v3.0.2
c1=635735 - v2.5.0
c1=551947 - v1.9.0
c2=1001
On Teensy 3.5 (120MHz ARM):
Start
c1=2690322
c2=1001
On esp8266 (80 MHz)
Start
c1=351085 (689833 at 160Mhz)
c2=1001
On STM32F103RCBT6 (Maple Mini @72 MHz)
Start
c1=4665019
c2=1001
C1 in scenario 2) is much higher than in scenario 1) because processor is put to sleep for 1), but not for 2)
*/
/**
* Compile and run once with _TASK_SLEEP_ON_IDLE_RUN enabled, then with _TASK_SLEEP_ON_IDLE_RUN disabled.
* Compare the results.
*/
//#define _TASK_SLEEP_ON_IDLE_RUN
#include <TaskScheduler.h>
Scheduler ts;
// Callback methods prototypes
void Count();
bool tOn(); void tOff();
// Tasks
Task c(10, TASK_FOREVER, &Count, &ts);
Task t(10000, TASK_ONCE, NULL, &ts, true, &tOn, &tOff);
volatile unsigned long c1, c2;
bool tOn() {
c1 = 0;
c2 = 0;
c.enable();
return true;
}
void tOff() {
c.disable();
Serial.print("c1=");Serial.println(c1);
Serial.print("c2=");Serial.println(c2);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(1000);
Serial.println("Start");
ts.startNow();
t.delay();
}
void Count() {
c2++;
}
void loop() {
// put your main code here, to run repeatedly:
ts.execute();
c1++;
}

View file

@ -0,0 +1,133 @@
/**
* TaskScheduler Test sketch - use of task IDs and watchdog timer to identify hung tasks
* THIS SKETCH RUNS ON AVR BOARDS ONLY
* Test case:
* Watchdog timer is set to 2 seconds (interrupt + reset)
* A hearbeat task (resetting the watchdog timer) is scheduled with 500 ms interval
* A number of tasks are running every 1 second and "rolling the dice" 0..19. If 5, task is made to enter infinite loop
* Device should reset in 2 seconds after a task enters infinite loop
* A task id and a control point number are saved to EEPROM prior to device reset, and are displayed after reboot.
* In real life, device might chose to NOT activate certain tasks which failed previously (failed sensors for instance)
*/
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_WDT_IDS
#include <TaskScheduler.h>
#include <EEPROM.h>
#include <avr/wdt.h>
Scheduler ts;
// Callback methods prototypes
void TaskCB();
void HB(); bool HBOn(); void HBOff();
// Three tasks emulating accidental infinite loop
Task tTask1(TASK_SECOND, TASK_FOREVER, &TaskCB, &ts, true);
Task tTask2(TASK_SECOND, TASK_FOREVER, &TaskCB, &ts, true);
Task tTask3(TASK_SECOND, TASK_FOREVER, &TaskCB, &ts, true);
// Heartbeat task - resetting the watchdog timer periodically
// Initiates WDT on enable, and deactivates it on disable
Task tHB(500, TASK_FOREVER, &HB, &ts, false, &HBOn, &HBOff);
/**
* Emulating task callback function
* Prints task id and randomly "hangs" in two places.
* Control points are stored on the task prior to section which might hang,
* making this information available to the WDT interrupt handler
*/
void TaskCB() {
Task& T = ts.currentTask();
Serial.print("Task #:");
Serial.print(T.getId());
Serial.print(" current iteration = ");
Serial.println(T.getRunCounter());
// Hang if random number between 0 and 19 is 5 (5% probability)
T.setControlPoint(10);
if (random(20) == 5) for(;;);
// Hang if random number between 0 and 99 is more that 95 (5% probability)
T.setControlPoint(95);
if (random(100) > 94) for(;;);
}
/**
* This On Enable method sets up the WDT
* for interrupt and reset after 2 seconds
*/
bool HBOn() {
//disable interrupts
cli();
//reset watchdog
wdt_reset();
//set up WDT interrupt
WDTCSR = (1<<WDCE)|(1<<WDE);
//Start watchdog timer with aDelay prescaller
WDTCSR = (1<<WDIE)|(1<<WDE)|(WDTO_2S & 0x2F);
// WDTCSR = (1<<WDIE)|(WDTO_2S & 0x2F); // interrupt only without reset
//Enable global interrupts
sei();
}
/**
* This On Disable method disables WDT
*/
void HBOff() {
wdt_disable();
}
/**
* This is a periodic reset of WDT
*/
void HB() {
wdt_reset();
}
/**
* Watchdog timeout ISR
*
*/
ISR(WDT_vect)
{
Task& T = ts.currentTask();
digitalWrite(13, HIGH);
EEPROM.write(0, (byte)T.getId());
EEPROM.write(1, (byte)T.getControlPoint());
digitalWrite(13, LOW);
}
/**
* Standard arduino setup routine
*/
void setup() {
Serial.begin(115200);
randomSeed(analogRead(0)+analogRead(5));
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
Serial.println("WDT heartbeat test");
Serial.print("Last task before reset="); Serial.println(EEPROM.read(0));
Serial.print("Last control point before reset="); Serial.println(EEPROM.read(1));
delay(2000);
tHB.enableDelayed();
}
/**
* Not much is left for the loop()
*/
void loop() {
ts.execute();
}

View file

@ -0,0 +1,147 @@
/**
* 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;
// Callback methods prototypes
void Calculate(); bool CalcOn();
bool WrapperOn(); void WrapperOff();
// Tasks
// Calculator tasks.
// Note that all three tasks use the same callback methods
// They will be updating specific variables based on the
// Locat Task Storage pointers
Task t1(TASK_SECOND, TASK_FOREVER, &Calculate, &ts, false, &CalcOn);
Task t2(TASK_SECOND, TASK_FOREVER, &Calculate, &ts, false, &CalcOn);
Task t3(TASK_SECOND, TASK_FOREVER, &Calculate, &ts, false, &CalcOn);
// add more calc tasks here if necessary
Task tWrapper(5*TASK_SECOND, TASK_ONCE, 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 loop 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();
}

View file

@ -0,0 +1,57 @@
/**
* TaskScheduler Test
* Illustration of use of Time Critical Information
*
* Task1 runs every 1 second indefinitely
* On each run it reports how delayed the invokation of the callback method was,
* and what was the scheduling overun.
* Each run task 1 is dealyed randomly for up to 2 seconds, thus simulating scheduling overrun
*/
#define _TASK_TIMECRITICAL
#define _TASK_SLEEP_ON_IDLE_RUN
#include <TaskScheduler.h>
// Callback methods prototypes
void t1Callback();
//Tasks
Task t1(1000, -1, &t1Callback);
Scheduler runner;
void t1Callback() {
Serial.print(millis());
Serial.print(": overrun = ");
Serial.print(t1.getOverrun());
Serial.print(", start delayed by ");
Serial.println(t1.getStartDelay());
int i = random(2000);
Serial.print("Delaying for "); Serial.println(i);
delay(i);
}
void setup () {
Serial.begin(115200);
Serial.println("Scheduler TimeCritical TEST");
runner.init();
Serial.println("Initialized scheduler");
runner.addTask(t1);
Serial.println("added t1. Waiting for 5 seconds.");
delay(5000);
t1.enable();
Serial.println("Enabled t1");
}
void loop () {
runner.execute();
}

View file

@ -0,0 +1,106 @@
/**
* This is a test to benchmark TaskScheduler execution.
*
* This test executes 1,000,000 cycles of a task with empty callback method
* Compiled with different options, you can assess the impact of each on the size of the Task object
* and the execution overhead of the main execution pass route.
*
* Sample execution times (in milliseconds per 1M iterations) are provided below.
* The test board is Arduino UNO 16MHz processor.
*
TaskScheduler 2.1.0:
No modifiers
Duration=19869
with SLEEP
Duration=20058
with status request:
Duration=20058
with time critical:
Duration=27289
TaskScheduler 1.9.0:
No modifiers
Duration=15656
with SLEEP
Duration=16285
with status request:
Duration=16600
with rollover fix:
Duration=18109
TaskScheduler 1.8.5:
Duration=15719
with SLEEP
Duration=16348
with status request:
Duration=18360
with rollover fix:
Duration=18423
*/
//#define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
//#define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
//#define _TASK_WDT_IDS // Compile with support for wdt control points and task ids
//#define _TASK_LTS_POINTER // Compile with support for local task storage pointer
//#define _TASK_SLEEP_ON_IDLE_RUN
//#define _TASK_MICRO_RES
#include <TaskScheduler.h>
Scheduler ts;
// Callback methods prototypes
bool tOn(); void tOff();
void callback();
// Tasks
Task t(TASK_IMMEDIATE, 1000000, &callback, &ts, false, &tOn, &tOff);
unsigned long c1, c2;
bool tOn() {
c1 = millis();
c2 = 0;
return true;
}
void tOff() {
c2 = millis();
Serial.println("done.");
Serial.print("Tstart =");Serial.println(c1);
Serial.print("Tfinish=");Serial.println(c2);
Serial.print("Duration=");Serial.println(c2-c1);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.print("Start...");
t.enable();
}
void callback() {
}
void loop() {
// put your main code here, to run repeatedly:
ts.execute();
}

View file

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

View file

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

View file

@ -0,0 +1,71 @@
/**
* TaskScheduler Test of microsecond scheduling resolution
*
* Task 1 runs starting with 211 microseconds intervals, doubling the interval on every iteration
* until it wraps when interval reaches about 72 minutes mark
*
* Task 2 provides heartbeat at a steady 5 seconds intervals
*
*/
#define _TASK_MICRO_RES
#include <TaskScheduler.h>
#define T1_INIT (211L)
Scheduler runner;
// Callback methods prototypes
void t1Callback();
void t1OnDisable();
void t2Callback();
unsigned long t1_interval = T1_INIT;
// Tasks
Task t1(t1_interval, 1, &t1Callback, &runner, true, NULL, &t1OnDisable); //adding task to the chain on creation
Task t2(5 * TASK_SECOND, TASK_FOREVER, &t2Callback, &runner, true); //adding task to the chain on creation
void t1Callback() {
unsigned long t = micros();
Serial.print("t1: ");
Serial.println(t);
}
void t1OnDisable() {
t1_interval += t1_interval;
if (t1_interval < T1_INIT) t1_interval = T1_INIT;
t1.setInterval(t1_interval);
t1.restartDelayed();
}
void t2Callback() {
unsigned long t = micros();
Serial.print("t2: ");
Serial.print(t);
Serial.println(" heartbeat");
}
void setup () {
Serial.begin(115200);
Serial.println("Scheduler TEST Microsecond Resolution");
Serial.println("5 seconds delay");
delay(5000);
runner.startNow(); // This creates a new scheduling starting point for all ACTIVE tasks.
// PLEASE NOTE - THIS METHOD DOES NOT ACTIVATE TASKS, JUST RESETS THE START TIME
t1.delay(); // Tasks which need to start delayed, need to be delayed again after startNow();
// Alternatively, tasks should be just enabled at the bottom of setup() method
// runner.enableAll();
// t1.delay();
}
void loop () {
runner.execute();
}

View file

@ -0,0 +1,339 @@
/**
This test illustrates the use if yield methods and internal StatusRequest objects
THIS TEST HAS BEEN TESTED ON NODEMCU V.2 (ESP8266)
The WiFi initialization and NTP update is executed in parallel to blinking the onboard LED
and an external LED connected to D2 (GPIO04)
Try running with and without correct WiFi parameters to observe the difference in behaviour
*/
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STATUS_REQUEST
#include <TaskScheduler.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
Scheduler ts;
// Callback methods prototypes
void connectInit();
void ledCallback();
bool ledOnEnable();
void ledOnDisable();
void ledOn();
void ledOff();
void ntpUpdateInit();
// Tasks
Task tConnect (TASK_SECOND, TASK_FOREVER, &connectInit, &ts, true);
Task tLED (TASK_IMMEDIATE, TASK_FOREVER, &ledCallback, &ts, false, &ledOnEnable, &ledOnDisable);
// Tasks running on events
Task tNtpUpdate (&ntpUpdateInit, &ts);
// Replace with WiFi parameters of your Access Point/Router:
const char *ssid = "wifi_network";
const char *pwd = "wifi_password";
long ledDelayOn, ledDelayOff;
#define LEDPIN D0 // Onboard LED pin - linked to WiFi
#define LEDPIN2 D2 // External LED
#define CONNECT_TIMEOUT 30 // Seconds
#define CONNECT_OK 0 // Status of successful connection to WiFi
#define CONNECT_FAILED (-99) // Status of failed connection to WiFi
// NTP Related Definitions
#define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes of the message
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
unsigned long epoch;
WiFiUDP udp; // A UDP instance to let us send and receive packets over UDP
#define LOCAL_NTP_PORT 2390 // Local UDP port for NTP update
void setup() {
Serial.begin(74880);
Serial.println(F("TaskScheduler test #14 - Yield and internal StatusRequests"));
Serial.println(F("=========================================================="));
Serial.println();
pinMode (LEDPIN, OUTPUT);
pinMode (LEDPIN2, OUTPUT);
tNtpUpdate.waitFor( tConnect.getInternalStatusRequest() ); // NTP Task will start only after connection is made
}
void loop() {
ts.execute(); // Only Scheduler should be executed in the loop
}
/**
Initiate connection to the WiFi network
*/
void connectInit() {
Serial.print(millis());
Serial.println(F(": connectInit."));
Serial.println(F("WiFi parameters: "));
Serial.print(F("SSID: ")); Serial.println(ssid);
Serial.print(F("PWD : ")); Serial.println(pwd);
WiFi.mode(WIFI_STA);
WiFi.hostname("esp8266");
WiFi.begin(ssid, pwd);
yield();
ledDelayOn = TASK_SECOND / 2;
ledDelayOff = TASK_SECOND / 4;
tLED.enable();
tConnect.yield(&connectCheck); // This will pass control back to Scheduler and then continue with connection checking
}
/**
Periodically check if connected to WiFi
Re-request connection every 5 seconds
Stop trying after a timeout
*/
void connectCheck() {
Serial.print(millis());
Serial.println(F(": connectCheck."));
if (WiFi.status() == WL_CONNECTED) { // Connection established
Serial.print(millis());
Serial.print(F(": Connected to AP. Local ip: "));
Serial.println(WiFi.localIP());
tConnect.disable();
}
else {
if (tConnect.getRunCounter() % 5 == 0) { // re-request connection every 5 seconds
Serial.print(millis());
Serial.println(F(": Re-requesting connection to AP..."));
WiFi.disconnect(true);
yield(); // This is an esp8266 standard yield to allow linux wifi stack run
WiFi.hostname("esp8266");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pwd);
yield(); // This is an esp8266 standard yield to allow linux wifi stack run
}
if (tConnect.getRunCounter() == CONNECT_TIMEOUT) { // Connection Timeout
tConnect.getInternalStatusRequest()->signal(CONNECT_FAILED); // Signal unsuccessful completion
tConnect.disable();
Serial.print(millis());
Serial.println(F(": connectOnDisable."));
Serial.print(millis());
Serial.println(F(": Unable to connect to WiFi."));
ledDelayOn = TASK_SECOND / 16; // Blink LEDs quickly due to error
ledDelayOff = TASK_SECOND / 16;
tLED.enable();
}
}
}
/**
Initiate NTP update if connection was established
*/
void ntpUpdateInit() {
Serial.print(millis());
Serial.println(F(": ntpUpdateInit."));
if ( tConnect.getInternalStatusRequest()->getStatus() != CONNECT_OK ) { // Check status of the Connect Task
Serial.print(millis());
Serial.println(F(": cannot update NTP - not connected."));
return;
}
udp.begin(LOCAL_NTP_PORT);
if ( WiFi.hostByName(ntpServerName, timeServerIP) ) { //get a random server from the pool
Serial.print(millis());
Serial.print(F(": timeServerIP = "));
Serial.println(timeServerIP);
sendNTPpacket(timeServerIP); // send an NTP packet to a time server
}
else {
Serial.print(millis());
Serial.println(F(": NTP server address lookup failed."));
tLED.disable();
udp.stop();
tNtpUpdate.disable();
return;
}
ledDelayOn = TASK_SECOND / 8;
ledDelayOff = TASK_SECOND / 8;
tLED.enable();
tNtpUpdate.set( TASK_SECOND, CONNECT_TIMEOUT, &ntpCheck );
tNtpUpdate.enableDelayed();
}
/**
* Check if NTP packet was received
* Re-request every 5 seconds
* Stop trying after a timeout
*/
void ntpCheck() {
Serial.print(millis());
Serial.println(F(": ntpCheck."));
if ( tNtpUpdate.getRunCounter() % 5 == 0) {
Serial.print(millis());
Serial.println(F(": Re-requesting NTP update..."));
udp.stop();
yield();
udp.begin(LOCAL_NTP_PORT);
sendNTPpacket(timeServerIP);
return;
}
if ( doNtpUpdateCheck()) {
Serial.print(millis());
Serial.println(F(": NTP Update successful"));
Serial.print(millis());
Serial.print(F(": Unix time = "));
Serial.println(epoch);
tLED.disable();
tNtpUpdate.disable();
udp.stop();
}
else {
if ( tNtpUpdate.isLastIteration() ) {
Serial.print(millis());
Serial.println(F(": NTP Update failed"));
tLED.disable();
udp.stop();
}
}
}
/**
* Send NTP packet to NTP server
*/
unsigned long sendNTPpacket(IPAddress & address)
{
Serial.print(millis());
Serial.println(F(": sendNTPpacket."));
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
udp.beginPacket(address, 123); //NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
yield();
}
/**
* Check if a packet was recieved.
* Process NTP information if yes
*/
bool doNtpUpdateCheck() {
Serial.print(millis());
Serial.println(F(": doNtpUpdateCheck."));
yield();
int cb = udp.parsePacket();
if (cb) {
// We've received a packet, read the data from it
udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
// now convert NTP time into everyday time:
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
epoch = secsSince1900 - seventyYears;
return (epoch != 0);
}
return false;
}
/**
* Flip the LED state based on the current state
*/
bool ledState;
void ledCallback() {
if ( ledState ) ledOff();
else ledOn();
}
/**
* Make sure the LED starts lit
*/
bool ledOnEnable() {
ledOn();
return true;
}
/**
* Make sure LED ends dimmed
*/
void ledOnDisable() {
ledOff();
}
/**
* Turn LEDs on.
* Set appropriate delay.
* PLEASE NOTE: NodeMCU onbaord LED is active-low
*/
void ledOn() {
ledState = true;
digitalWrite(LEDPIN, LOW);
digitalWrite(LEDPIN2, HIGH);
tLED.delay( ledDelayOn );
}
/**
* Turn LEDs off.
* Set appropriate delay.
* PLEASE NOTE: NodeMCU onbaord LED is active-low
*/
void ledOff() {
ledState = false;
digitalWrite(LEDPIN, HIGH);
digitalWrite(LEDPIN2, LOW);
tLED.delay( ledDelayOff );
}

View file

@ -0,0 +1,53 @@
/**
* TaskScheduler Test sketch - Showing how to use std::function
* to get acces to variables from within the task callback function
*
* Support for std::function is only available for ESP8266 architecture
*/
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STD_FUNCTION // Compile with support for std::function
#include <TaskScheduler.h>
Scheduler ts;
int counter = 0;
class Calculator {
public:
int cumSum = 0; // cumulative sum
Calculator(int b) {
// Pass the this pointer, so that we get access to this->cumSum
// Also pass a copy of b
calculateTask.set(TASK_SECOND, TASK_FOREVER, [this, b]() {
counter++;
Serial.printf("%u. %u: cumSum = %u + %u\t", counter, millis(), cumSum, b);
cumSum += b;
Serial.printf("Resulting cumulative sum: %u\n", cumSum);
});
ts.addTask(calculateTask);
calculateTask.enable();
}
Task calculateTask;
};
Calculator calc1(2);
Calculator calc2(4);
Calculator calc3(8);
// Disable tasks after 10 seconds
Task tWrapper(10*TASK_SECOND, TASK_ONCE, []() {
ts.disableAll();
}, &ts);
/**
* Standard Arduino setup and loop methods
*/
void setup() {
Serial.begin(74880);
Serial.println("std::function test");
tWrapper.enableDelayed();
}
void loop() {
ts.execute();
}

View file

@ -0,0 +1,18 @@
//This file is intentionally left blank.
//
//Arduino IDE plays some dirty tricks on the main sketch .ino file:
//it rearranges #includes, blindly creates forward definitions,
//includes every file in the project that does not have .c or .cpp
//file extension.
//
//Usually it all turns well if you have only one source file and you are either
//inexperienced or really expert C++ Arduino programmer.
//For the folks with the middle ground skills level, when you want
//to split your code into several .cpp files, it is best to leave
//this main sketch empty.
//
//It doesn't matter where you define the void loop() and void setup().
//Just make sure there is exactly one definition of each.
//
//And if you want to use standard Arduino functions
//like digitalWrite or the Serial object - just add #include<Arduino.h>.

View file

@ -0,0 +1,31 @@
#include <Arduino.h>
#include "header.hpp"
//Declare the functions we want to use before we are ready to define them
void t1Callback();
// Tasks
Task t1(2000, 10, &t1Callback, &runner, true); //adding task to the chain on creation
Task t3(5000, TASK_FOREVER, &t3Callback);
void t1Callback() {
Serial.print("t1: ");
Serial.println(millis());
if (t1.isFirstIteration()) {
runner.addTask(t3);
t3.enable();
Serial.println("t1: enabled t3 and added to the chain");
}
if (t1.isLastIteration()) {
t3.disable();
runner.deleteTask(t3);
t2.setInterval(500);
Serial.println("t1: disable t3 and delete it from the chain. t2 interval set to 500");
}
}

View file

@ -0,0 +1,55 @@
// Test the same as example#2:
// Initially only tasks 1 and 2 are enabled
// Task1 runs every 2 seconds 10 times and then stops
// Task2 runs every 3 seconds indefinitely
// Task1 enables Task3 at its first run
// Task3 run every 5 seconds
// loop() runs every 1 second (a default scheduler delay, if no shorter tasks' interval is detected)
// Task1 disables Task3 on its last iteration and changed Task2 to run every 1/2 seconds
// Because Task2 interval is shorter than Scheduler default tick, loop() executes ecery 1/2 seconds now
// At the end Task2 is the only task running every 1/2 seconds
//Header that declares all shared objects between .cpp files
#include "header.hpp"
#include <Arduino.h> //for Serial and delay
Scheduler runner; //Let the scheduler live here, in the main file, ok?
//Pretend, that the t2 task is a special task,
//that needs to live in file2 object file.
void t2Callback() {
Serial.print("t2: ");
Serial.println(millis());
}
Task t2(3000, TASK_FOREVER, &t2Callback, &runner, true);
//Lets define t3Callback here. We are going to use it in file1
//for Task 1.
void t3Callback() {
Serial.print("t3: ");
Serial.println(millis());
}
void setup () {
Serial.begin(115200);
delay(5000);
Serial.println("Scheduler TEST (multi-tab)");
runner.startNow(); // set point-in-time for scheduling start
}
void loop () {
runner.execute();
// Serial.println("Loop ticks at: ");
// Serial.println(millis());
}

View file

@ -0,0 +1,15 @@
//This is the place to declare every single function
//and global variable that is going to be reused between cpp files.
//We are going to use the TaskScheduler, but only the declarations part.
//Remember to put customization macros before the #include:
#define _TASK_SLEEP_ON_IDLE_RUN
#include <TaskSchedulerDeclarations.h>
//Let the runner object be a global, single instance shared between object files.
extern Scheduler runner;
extern Task t2; //the t2 is defined in file2, but we need to access it from file1.
//This function needs to be shared (between file2 and file1).
void t3Callback();

View file

@ -0,0 +1,20 @@
//This is the only .cpp file that gets the #include<TaskScheduler.h>.
//Without it, the linker would not find necessary TaskScheduler's compiled code.
//
//Remember to put customization macros here as well.
//
//And don't import any common headers (here: header.hpp)
//
//Really. This file needs to be short. All stuff is in TaskScheduler.h.
// #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
// #define _TASK_PRIORITY // Support for layered scheduling priority
// #define _TASK_MICRO_RES // Support for microsecond resolution
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 ONLY)
// #define _TASK_DEBUG // Make all methods and variables public for debug purposes
#include <TaskScheduler.h>

View file

@ -0,0 +1,90 @@
/*
This eaxmple illustrates the use of overall Task timeout functionality:
Task 1 - runs every 1 seconds and times out in 10 seconds
Task 2 - runs every 5 seconds and resets the timeout every run, so runs continuosly even though the timeout is set to 10 seconds
*/
// #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
// #define _TASK_PRIORITY // Support for layered scheduling priority
// #define _TASK_MICRO_RES // Support for microsecond resolution
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 ONLY)
// #define _TASK_DEBUG // Make all methods and variables public for debug purposes
// #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
#define _TASK_TIMEOUT
#include <TaskScheduler.h>
Scheduler ts;
void task1Callback();
void task1OnDisable();
void task2Callback();
void task2OnDisable();
Task t1(1 * TASK_SECOND, TASK_FOREVER, &task1Callback, &ts, false, NULL, &task1OnDisable);
Task t2(5 * TASK_SECOND, TASK_FOREVER, &task2Callback, &ts, false, NULL, &task2OnDisable);
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("TaskScheduler Timeout example");
Serial.println("=============================");
t1.setTimeout(10 * TASK_SECOND);
t2.setTimeout(10 * TASK_SECOND);
ts.enableAll();
}
void loop() {
// put your main code here, to run repeatedly:
ts.execute();
}
void task1Callback() {
Serial.print("Task 1:\t");
Serial.print(millis());
Serial.print(": t/out=");
Serial.print(t1.getTimeout());
Serial.print("\tms until t/out=");
Serial.println( t1.untilTimeout());
}
void task1OnDisable() {
if (t1.timedOut()) {
Serial.println("Task 1 has timed out. Restarting");
t1.setInterval(1 * TASK_SECOND);
t1.setIterations(15);
t1.setTimeout(TASK_NOTIMEOUT);
t1.enable();
}
else {
Serial.println("Task 1 has been disabled");
}
}
void task2Callback() {
Serial.print("Task 2:\t");
Serial.print(millis());
Serial.print(": t/out=");
Serial.print(t2.getTimeout());
Serial.print("\tms until t/out=");
Serial.println( t2.untilTimeout());
t2.resetTimeout();
}
void task2OnDisable() {
if (t2.timedOut()) {
Serial.println("Task 2 has timed out");
}
else {
Serial.println("Task 2 has been disabled");
}
}

View file

@ -0,0 +1,172 @@
/**
This is example 5 rewritten with Timeout, LTS and WDT functioanlity:
- 1 second timeout is set for the main calculation task
- LTS is used to address individual array elements for each sensor sinlce the callback code is shared
- WDT is used to set the Task ID and use that as an index for array of distances (alternative to LTS)
Original description:
====================
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.
Example5:
Sketch uses 6066 bytes (18%) of program storage space. Maximum is 32256 bytes.
Global variables use 1039 bytes (50%) of dynamic memory, leaving 1009 bytes for local variables. Maximum is 2048 bytes.
Example 18:
Sketch uses 5142 bytes (15%) of program storage space. Maximum is 32256 bytes.
Global variables use 878 bytes (42%) of dynamic memory, leaving 1170 bytes for local variables. Maximum is 2048 bytes.
*/
// #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
#define _TASK_PRIORITY // Support for layered scheduling priority
// #define _TASK_MICRO_RES // Support for microsecond resolution
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 and ESP32 ONLY)
#define _TASK_DEBUG // Make all methods and variables public for debug purposes
#define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
#define _TASK_TIMEOUT // Support for overall task timeout
#include <TaskScheduler.h>
StatusRequest measure;
Scheduler ts, hts;
// Callback methods prototypes
void CycleCallback();
void CalcCallback();
bool CalcEnable();
void CalcDisable();
void SCallback(); bool SEnable();
// Tasks
Task tSensor1(0, TASK_ONCE, &SCallback, &ts, false, &SEnable); // task ID = 1
Task tSensor2(0, TASK_ONCE, &SCallback, &ts, false, &SEnable); // task ID = 2
Task tSensor3(0, TASK_ONCE, &SCallback, &ts, false, &SEnable); // task ID = 3
Task tCycle(10000, TASK_FOREVER, &CycleCallback, &hts);
Task tCalculate(TASK_IMMEDIATE , TASK_ONCE, &CalcCallback, &hts, false, &CalcEnable, &CalcDisable);
#define NO_OF_SENSORS 3
long distance, d[NO_OF_SENSORS + 1], d_lts[NO_OF_SENSORS]; // d[] will be populated via task ID used as array indexes, d_lts will be addressed via LTS pointers
void CycleCallback() {
Serial.println();
Serial.print(millis()); Serial.print(":\t");
Serial.println("CycleCallback: Initiating measurement cycle every 10 seconds");
distance = 0;
measure.setWaiting(NO_OF_SENSORS); // Set the StatusRequest to wait for 3 signals.
tCalculate.waitFor(&measure);
}
bool CalcEnable() {
Serial.print(millis()); Serial.print(":\t");
Serial.println("CalcEnable: OnEnable");
Serial.println("Activating sensors and setting timeout");
tSensor1.restartDelayed();
tSensor2.restartDelayed();
tSensor3.restartDelayed();
return true;
}
void CalcDisable() {
if (tCalculate.timedOut()) {
measure.signalComplete(-1); // signal error
Serial.print(millis()); Serial.print(":\t");
Serial.println("MeasureCallback: ***** Timeout *****");
// tSensor1.disable();
// tSensor2.disable();
// tSensor3.disable();
}
}
void CalcCallback() {
Serial.print(millis()); Serial.print(":\t");
Serial.println("CalcCallback: calculating");
distance = -1;
if ( measure.getStatus() >= 0) { // only calculate if statusrequest ended successfully
distance = d[1] < d[2] ? d[1] : d[2];
distance = d[3] < distance ? d[3] : distance;
Serial.print("CalcCallback: Min distance="); Serial.println(distance);
Serial.println();
}
}
/** Simulation code for all sensors
-------------------------------
*/
bool SEnable() {
Task &t = ts.currentTask();
int i = t.getId();
Serial.print(millis()); Serial.print(":\t");
Serial.print("SEnable: TaskID=");
Serial.println(i);
Serial.print("Triggering sensor. Delay=");
t.setInterval( random(1200) ); // Simulating sensor delay, which could go over 1 second and cause timeout
// One way to update the 3 distances with one codebase - use task id as an index
d[i] = 0;
// Another way to update the 3 distances with one codebase - use LTS pointers
int *pd = (int*) t.getLtsPointer();
*pd = 0;
Serial.println( t.getInterval() );
return true;
}
void SCallback() {
Task &t = ts.currentTask();
int i = t.getId();
Serial.print(millis()); Serial.print(":\t");
Serial.print("SCallback: TaskID=");
Serial.println(i);
Serial.print("Emulating measurement. d=");
d[i] = random(501); // pick a value from 0 to 500 "centimeters" simulating a measurement
int *pd = (int*) t.getLtsPointer();
*pd = d[i];
measure.signal();
Serial.print(d[i]);
Serial.print("\t");
Serial.println(*pd);
}
/** 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(A0) + millis());
tSensor1.setLtsPointer(&d_lts[0]);
tSensor2.setLtsPointer(&d_lts[1]);
tSensor3.setLtsPointer(&d_lts[2]);
ts.setHighPriorityScheduler(&hts);
tCalculate.setTimeout(1 * TASK_SECOND);
tCycle.enable();
}
void loop() {
ts.execute();
}

View file

@ -0,0 +1,540 @@
/**
TaskScheduler Test sketch - test of Task destructor
Test case:
Main task runs every 100 milliseconds 100 times and in 50% cases generates a task object
which runs 1 to 10 times with 100 ms to 5 s interval, and then destroyed.
This sketch uses a FreeMemory library: https://github.com/McNeight/MemoryFree
*/
#define _TASK_WDT_IDS // To enable task unique IDs
#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_LTS_POINTER // Compile with support for Local Task Storage pointer
#include <TaskScheduler.h>
#include <MemoryFree.h>
Scheduler ts;
// Callback methods prototypes
void MainLoop();
// Statis task
Task tMain(100*TASK_MILLISECOND, 100, MainLoop, &ts, true);
void Iteration();
bool OnEnable();
void OnDisable();
int noOfTasks = 0;
void MainLoop() {
Serial.print(millis()); Serial.print("\t");
Serial.print("MainLoop run: ");
int i = tMain.getRunCounter();
Serial.print(i); Serial.print(F(".\t"));
if ( random(0, 101) > 50 ) { // generate a new task only in 50% of cases
// Generating another task
long p = random(100, 5001); // from 100 ms to 5 seconds
long j = random(1, 11); // from 1 to 10 iterations)
Task *t = new Task(p, j, Iteration, &ts, false, OnEnable, OnDisable);
Serial.print(F("Generated a new task:\t")); Serial.print(t->getId()); Serial.print(F("\tInt, Iter = \t"));
Serial.print(p); Serial.print(", "); Serial.print(j); Serial.print(F("\tFree mem="));
Serial.print(freeMemory()); Serial.print(F("\tNo of tasks=")); Serial.println(++noOfTasks);
t->enable();
}
else {
Serial.println(F("Skipped generating a task"));
}
}
void Iteration() {
Task &t = ts.currentTask();
Serial.print(millis()); Serial.print("\t");
Serial.print("Task N"); Serial.print(t.getId()); Serial.print(F("\tcurrent iteration: "));
int i = t.getRunCounter();
Serial.println(i);
}
bool OnEnable() {
// to-do: think of something to put in here.
return true;
}
void OnDisable() {
Task *t = &ts.currentTask();
unsigned int tid = t->getId();
delete t;
Serial.print(millis()); Serial.print("\t");
Serial.print("Task N"); Serial.print(tid); Serial.print(F("\tfinished and destroyed.\tFree mem="));
Serial.print(freeMemory());Serial.print(F("\tNo of tasks=")); Serial.println(--noOfTasks);
}
/**
Standard Arduino setup and loop methods
*/
void setup() {
Serial.begin(115200);
randomSeed(analogRead(0) + analogRead(5));
noOfTasks = 0;
Serial.println(F("Dynamic Task Creation/Destruction Example"));
Serial.println();
Serial.print(F("Free mem="));
Serial.print(freeMemory()); Serial.print(F("\tNo of tasks=")); Serial.println(noOfTasks);
Serial.println();
}
void loop() {
ts.execute();
}
/* Output on Arduino Uno:
*
* Compile:
Sketch uses 5312 bytes (16%) of program storage space. Maximum is 32256 bytes.
Global variables use 282 bytes (13%) of dynamic memory, leaving 1766 bytes for local variables. Maximum is 2048 bytes.
* Execution:
Dynamic Task Creation/Destruction Example
Free mem=1758 No of tasks=0
1 MainLoop run: 1. Generated a new task: 2 Int, Iter = 421, 3 Free mem=1701 No of tasks=1
8 Task N2 current iteration: 1
100 MainLoop run: 2. Generated a new task: 3 Int, Iter = 4099, 9 Free mem=1656 No of tasks=2
102 Task N3 current iteration: 1
200 MainLoop run: 3. Skipped generating a task
300 MainLoop run: 4. Generated a new task: 4 Int, Iter = 1795, 1 Free mem=1611 No of tasks=3
302 Task N4 current iteration: 1
305 Task N4 finished and destroyed. Free mem=1613 No of tasks=2
400 MainLoop run: 5. Skipped generating a task
429 Task N2 current iteration: 2
500 MainLoop run: 6. Skipped generating a task
600 MainLoop run: 7. Skipped generating a task
700 MainLoop run: 8. Generated a new task: 5 Int, Iter = 4623, 7 Free mem=1611 No of tasks=3
702 Task N5 current iteration: 1
800 MainLoop run: 9. Generated a new task: 6 Int, Iter = 4987, 4 Free mem=1566 No of tasks=4
802 Task N6 current iteration: 1
850 Task N2 current iteration: 3
850 Task N2 finished and destroyed. Free mem=1568 No of tasks=3
900 MainLoop run: 10. Generated a new task: 7 Int, Iter = 600, 4 Free mem=1566 No of tasks=4
902 Task N7 current iteration: 1
1000 MainLoop run: 11. Skipped generating a task
1100 MainLoop run: 12. Generated a new task: 8 Int, Iter = 2530, 1 Free mem=1521 No of tasks=5
1102 Task N8 current iteration: 1
1105 Task N8 finished and destroyed. Free mem=1523 No of tasks=4
1200 MainLoop run: 13. Skipped generating a task
1300 MainLoop run: 14. Generated a new task: 9 Int, Iter = 2215, 7 Free mem=1521 No of tasks=5
1302 Task N9 current iteration: 1
1400 MainLoop run: 15. Skipped generating a task
1500 MainLoop run: 16. Skipped generating a task
1502 Task N7 current iteration: 2
1600 MainLoop run: 17. Skipped generating a task
1700 MainLoop run: 18. Skipped generating a task
1800 MainLoop run: 19. Skipped generating a task
1900 MainLoop run: 20. Skipped generating a task
2000 MainLoop run: 21. Generated a new task: 10 Int, Iter = 189, 10 Free mem=1476 No of tasks=6
2002 Task N10 current iteration: 1
2100 MainLoop run: 22. Generated a new task: 11 Int, Iter = 2898, 9 Free mem=1431 No of tasks=7
2102 Task N7 current iteration: 3
2105 Task N11 current iteration: 1
2191 Task N10 current iteration: 2
2200 MainLoop run: 23. Generated a new task: 12 Int, Iter = 1691, 6 Free mem=1386 No of tasks=8
2202 Task N12 current iteration: 1
2300 MainLoop run: 24. Generated a new task: 13 Int, Iter = 1448, 7 Free mem=1341 No of tasks=9
2304 Task N13 current iteration: 1
2380 Task N10 current iteration: 3
2400 MainLoop run: 25. Generated a new task: 14 Int, Iter = 3919, 7 Free mem=1296 No of tasks=10
2403 Task N14 current iteration: 1
2500 MainLoop run: 26. Generated a new task: 15 Int, Iter = 3745, 5 Free mem=1251 No of tasks=11
2503 Task N15 current iteration: 1
2569 Task N10 current iteration: 4
2600 MainLoop run: 27. Skipped generating a task
2700 MainLoop run: 28. Skipped generating a task
2702 Task N7 current iteration: 4
2702 Task N7 finished and destroyed. Free mem=1253 No of tasks=10
2758 Task N10 current iteration: 5
2800 MainLoop run: 29. Generated a new task: 16 Int, Iter = 2144, 1 Free mem=1251 No of tasks=11
2803 Task N16 current iteration: 1
2806 Task N16 finished and destroyed. Free mem=1253 No of tasks=10
2900 MainLoop run: 30. Generated a new task: 17 Int, Iter = 4618, 10 Free mem=1251 No of tasks=11
2904 Task N17 current iteration: 1
2947 Task N10 current iteration: 6
3000 MainLoop run: 31. Skipped generating a task
3100 MainLoop run: 32. Generated a new task: 18 Int, Iter = 2885, 6 Free mem=1206 No of tasks=12
3103 Task N18 current iteration: 1
3136 Task N10 current iteration: 7
3200 MainLoop run: 33. Skipped generating a task
3300 MainLoop run: 34. Skipped generating a task
3325 Task N10 current iteration: 8
3400 MainLoop run: 35. Skipped generating a task
3500 MainLoop run: 36. Generated a new task: 19 Int, Iter = 2250, 4 Free mem=1161 No of tasks=13
3503 Task N19 current iteration: 1
3514 Task N10 current iteration: 9
3518 Task N9 current iteration: 2
3600 MainLoop run: 37. Skipped generating a task
3700 MainLoop run: 38. Generated a new task: 20 Int, Iter = 1689, 7 Free mem=1116 No of tasks=14
3703 Task N10 current iteration: 10
3706 Task N20 current iteration: 1
3709 Task N10 finished and destroyed. Free mem=1118 No of tasks=13
3750 Task N13 current iteration: 2
3800 MainLoop run: 39. Generated a new task: 21 Int, Iter = 2607, 5 Free mem=1116 No of tasks=14
3803 Task N21 current iteration: 1
3893 Task N12 current iteration: 2
3900 MainLoop run: 40. Generated a new task: 22 Int, Iter = 1390, 6 Free mem=1071 No of tasks=15
3903 Task N22 current iteration: 1
4000 MainLoop run: 41. Generated a new task: 23 Int, Iter = 3340, 8 Free mem=1026 No of tasks=16
4003 Task N23 current iteration: 1
4100 MainLoop run: 42. Skipped generating a task
4200 MainLoop run: 43. Skipped generating a task
4201 Task N3 current iteration: 2
4300 MainLoop run: 44. Skipped generating a task
4400 MainLoop run: 45. Generated a new task: 24 Int, Iter = 4083, 2 Free mem=981 No of tasks=17
4403 Task N24 current iteration: 1
4500 MainLoop run: 46. Generated a new task: 25 Int, Iter = 4510, 1 Free mem=936 No of tasks=18
4503 Task N25 current iteration: 1
4506 Task N25 finished and destroyed. Free mem=938 No of tasks=17
4600 MainLoop run: 47. Generated a new task: 26 Int, Iter = 4782, 10 Free mem=936 No of tasks=18
4603 Task N26 current iteration: 1
4700 MainLoop run: 48. Generated a new task: 27 Int, Iter = 641, 6 Free mem=891 No of tasks=19
4702 Task N27 current iteration: 1
4800 MainLoop run: 49. Generated a new task: 28 Int, Iter = 695, 5 Free mem=846 No of tasks=20
4802 Task N28 current iteration: 1
4900 MainLoop run: 50. Generated a new task: 29 Int, Iter = 3520, 3 Free mem=801 No of tasks=21
4903 Task N29 current iteration: 1
5000 MainLoop run: 51. Generated a new task: 30 Int, Iter = 3091, 9 Free mem=756 No of tasks=22
5002 Task N11 current iteration: 2
5006 Task N30 current iteration: 1
5100 MainLoop run: 52. Skipped generating a task
5198 Task N13 current iteration: 3
5200 MainLoop run: 53. Skipped generating a task
5293 Task N22 current iteration: 2
5300 MainLoop run: 54. Generated a new task: 31 Int, Iter = 4359, 9 Free mem=711 No of tasks=23
5303 Task N31 current iteration: 1
5325 Task N5 current iteration: 2
5343 Task N27 current iteration: 2
5392 Task N20 current iteration: 2
5400 MainLoop run: 55. Generated a new task: 32 Int, Iter = 837, 4 Free mem=666 No of tasks=24
5403 Task N32 current iteration: 1
5497 Task N28 current iteration: 2
5501 MainLoop run: 56. Generated a new task: 33 Int, Iter = 274, 8 Free mem=621 No of tasks=25
5505 Task N33 current iteration: 1
5584 Task N12 current iteration: 3
5600 MainLoop run: 57. Generated a new task: 34 Int, Iter = 923, 7 Free mem=576 No of tasks=26
5603 Task N34 current iteration: 1
5700 MainLoop run: 58. Generated a new task: 35 Int, Iter = 1007, 8 Free mem=531 No of tasks=27
5703 Task N35 current iteration: 1
5732 Task N9 current iteration: 3
5753 Task N19 current iteration: 2
5778 Task N33 current iteration: 2
5789 Task N6 current iteration: 2
5800 MainLoop run: 59. Skipped generating a task
5900 MainLoop run: 60. Generated a new task: 36 Int, Iter = 608, 4 Free mem=486 No of tasks=28
5903 Task N36 current iteration: 1
5984 Task N27 current iteration: 3
5988 Task N18 current iteration: 2
6000 MainLoop run: 61. Generated a new task: 37 Int, Iter = 4043, 3 Free mem=441 No of tasks=29
6003 Task N37 current iteration: 1
6052 Task N33 current iteration: 3
6100 MainLoop run: 62. Skipped generating a task
6192 Task N28 current iteration: 3
6200 MainLoop run: 63. Skipped generating a task
6239 Task N32 current iteration: 2
6248 Task N15 current iteration: 2
6300 MainLoop run: 64. Skipped generating a task
6322 Task N14 current iteration: 2
6326 Task N33 current iteration: 4
6400 MainLoop run: 65. Skipped generating a task
6410 Task N21 current iteration: 2
6500 MainLoop run: 66. Skipped generating a task
6510 Task N36 current iteration: 2
6525 Task N34 current iteration: 2
6600 MainLoop run: 67. Skipped generating a task
6600 Task N33 current iteration: 5
6625 Task N27 current iteration: 4
6646 Task N13 current iteration: 4
6683 Task N22 current iteration: 3
6700 MainLoop run: 68. Generated a new task: 38 Int, Iter = 1907, 9 Free mem=396 No of tasks=30
6703 Task N38 current iteration: 1
6709 Task N35 current iteration: 2
6800 MainLoop run: 69. Skipped generating a task
6874 Task N33 current iteration: 6
6887 Task N28 current iteration: 4
6900 MainLoop run: 70. Generated a new task: 39 Int, Iter = 2697, 1 Free mem=351 No of tasks=31
6903 Task N39 current iteration: 1
6906 Task N39 finished and destroyed. Free mem=353 No of tasks=30
7000 MainLoop run: 71. Generated a new task: 40 Int, Iter = 2849, 4 Free mem=351 No of tasks=31
7003 Task N40 current iteration: 1
7076 Task N32 current iteration: 3
7081 Task N20 current iteration: 3
7100 MainLoop run: 72. Skipped generating a task
7118 Task N36 current iteration: 3
7148 Task N33 current iteration: 7
7200 MainLoop run: 73. Skipped generating a task
7266 Task N27 current iteration: 5
7275 Task N12 current iteration: 4
7300 MainLoop run: 74. Generated a new task: 41 Int, Iter = 4466, 4 Free mem=306 No of tasks=32
7303 Task N41 current iteration: 1
7343 Task N23 current iteration: 2
7400 MainLoop run: 75. Skipped generating a task
7422 Task N33 current iteration: 8
7422 Task N33 finished and destroyed. Free mem=308 No of tasks=31
7448 Task N34 current iteration: 3
7500 MainLoop run: 76. Generated a new task: 42 Int, Iter = 2133, 3 Free mem=306 No of tasks=32
7503 Task N42 current iteration: 1
7522 Task N17 current iteration: 2
7582 Task N28 current iteration: 5
7582 Task N28 finished and destroyed. Free mem=308 No of tasks=31
7600 MainLoop run: 77. Skipped generating a task
7700 MainLoop run: 78. Skipped generating a task
7716 Task N35 current iteration: 3
7726 Task N36 current iteration: 4
7726 Task N36 finished and destroyed. Free mem=353 No of tasks=30
7800 MainLoop run: 79. Generated a new task: 43 Int, Iter = 4113, 6 Free mem=351 No of tasks=31
7803 Task N43 current iteration: 1
7898 Task N11 current iteration: 3
7900 MainLoop run: 80. Skipped generating a task
7907 Task N27 current iteration: 6
7907 Task N27 finished and destroyed. Free mem=353 No of tasks=30
7913 Task N32 current iteration: 4
7913 Task N32 finished and destroyed. Free mem=398 No of tasks=29
7947 Task N9 current iteration: 4
8000 MainLoop run: 81. Skipped generating a task
8003 Task N19 current iteration: 3
8073 Task N22 current iteration: 4
8093 Task N30 current iteration: 2
8094 Task N13 current iteration: 5
8100 MainLoop run: 82. Skipped generating a task
8200 MainLoop run: 83. Generated a new task: 44 Int, Iter = 3389, 1 Free mem=396 No of tasks=30
8203 Task N44 current iteration: 1
8206 Task N44 finished and destroyed. Free mem=398 No of tasks=29
8300 MainLoop run: 84. Generated a new task: 45 Int, Iter = 3548, 10 Free mem=396 No of tasks=30
8303 Task N3 current iteration: 3
8306 Task N45 current iteration: 1
8371 Task N34 current iteration: 4
8400 MainLoop run: 85. Skipped generating a task
8422 Task N29 current iteration: 2
8485 Task N24 current iteration: 2
8485 Task N24 finished and destroyed. Free mem=398 No of tasks=29
8500 MainLoop run: 86. Generated a new task: 46 Int, Iter = 4962, 2 Free mem=396 No of tasks=30
8503 Task N46 current iteration: 1
8600 MainLoop run: 87. Skipped generating a task
8609 Task N38 current iteration: 2
8700 MainLoop run: 88. Skipped generating a task
8723 Task N35 current iteration: 4
8770 Task N20 current iteration: 4
8800 MainLoop run: 89. Skipped generating a task
8873 Task N18 current iteration: 3
8900 MainLoop run: 90. Skipped generating a task
8966 Task N12 current iteration: 5
9000 MainLoop run: 91. Skipped generating a task
9017 Task N21 current iteration: 3
9100 MainLoop run: 92. Skipped generating a task
9200 MainLoop run: 93. Skipped generating a task
9294 Task N34 current iteration: 5
9300 MainLoop run: 94. Skipped generating a task
9385 Task N26 current iteration: 2
9400 MainLoop run: 95. Generated a new task: 47 Int, Iter = 3556, 9 Free mem=351 No of tasks=31
9403 Task N47 current iteration: 1
9463 Task N22 current iteration: 5
9500 MainLoop run: 96. Generated a new task: 48 Int, Iter = 1226, 3 Free mem=306 No of tasks=32
9503 Task N48 current iteration: 1
9542 Task N13 current iteration: 6
9600 MainLoop run: 97. Generated a new task: 49 Int, Iter = 2850, 9 Free mem=261 No of tasks=33
9603 Task N49 current iteration: 1
9635 Task N42 current iteration: 2
9661 Task N31 current iteration: 2
9700 MainLoop run: 98. Skipped generating a task
9730 Task N35 current iteration: 5
9800 MainLoop run: 99. Generated a new task: 50 Int, Iter = 2782, 10 Free mem=216 No of tasks=34
9803 Task N50 current iteration: 1
9851 Task N40 current iteration: 2
9900 MainLoop run: 100. Skipped generating a task
9948 Task N5 current iteration: 3
9993 Task N15 current iteration: 3
10045 Task N37 current iteration: 2
10162 Task N9 current iteration: 5
10217 Task N34 current iteration: 6
10241 Task N14 current iteration: 3
10253 Task N19 current iteration: 4
10253 Task N19 finished and destroyed. Free mem=218 No of tasks=33
10459 Task N20 current iteration: 5
10516 Task N38 current iteration: 3
10657 Task N12 current iteration: 6
10657 Task N12 finished and destroyed. Free mem=263 No of tasks=32
10683 Task N23 current iteration: 3
10728 Task N48 current iteration: 2
10737 Task N35 current iteration: 6
10776 Task N6 current iteration: 3
10796 Task N11 current iteration: 4
10853 Task N22 current iteration: 6
10853 Task N22 finished and destroyed. Free mem=308 No of tasks=31
10990 Task N13 current iteration: 7
10990 Task N13 finished and destroyed. Free mem=353 No of tasks=30
11140 Task N34 current iteration: 7
11140 Task N34 finished and destroyed. Free mem=398 No of tasks=29
11184 Task N30 current iteration: 3
11624 Task N21 current iteration: 4
11744 Task N35 current iteration: 7
11758 Task N18 current iteration: 4
11768 Task N41 current iteration: 2
11768 Task N42 current iteration: 3
11769 Task N42 finished and destroyed. Free mem=443 No of tasks=28
11851 Task N45 current iteration: 2
11915 Task N43 current iteration: 2
11942 Task N29 current iteration: 3
11942 Task N29 finished and destroyed. Free mem=488 No of tasks=27
11954 Task N48 current iteration: 3
11954 Task N48 finished and destroyed. Free mem=533 No of tasks=26
12140 Task N17 current iteration: 3
12148 Task N20 current iteration: 6
12377 Task N9 current iteration: 6
12399 Task N3 current iteration: 4
12423 Task N38 current iteration: 4
12452 Task N49 current iteration: 2
12585 Task N50 current iteration: 2
12700 Task N40 current iteration: 3
12751 Task N35 current iteration: 8
12751 Task N35 finished and destroyed. Free mem=578 No of tasks=25
12958 Task N47 current iteration: 2
13464 Task N46 current iteration: 2
13464 Task N46 finished and destroyed. Free mem=623 No of tasks=24
13694 Task N11 current iteration: 5
13739 Task N15 current iteration: 4
13837 Task N20 current iteration: 7
13837 Task N20 finished and destroyed. Free mem=668 No of tasks=23
14020 Task N31 current iteration: 3
14023 Task N23 current iteration: 4
14088 Task N37 current iteration: 3
14088 Task N37 finished and destroyed. Free mem=713 No of tasks=22
14160 Task N14 current iteration: 4
14167 Task N26 current iteration: 3
14231 Task N21 current iteration: 5
14231 Task N21 finished and destroyed. Free mem=758 No of tasks=21
14275 Task N30 current iteration: 4
14330 Task N38 current iteration: 5
14571 Task N5 current iteration: 4
14592 Task N9 current iteration: 7
14592 Task N9 finished and destroyed. Free mem=803 No of tasks=20
14643 Task N18 current iteration: 5
15302 Task N49 current iteration: 3
15367 Task N50 current iteration: 3
15399 Task N45 current iteration: 3
15549 Task N40 current iteration: 4
15549 Task N40 finished and destroyed. Free mem=848 No of tasks=19
15763 Task N6 current iteration: 4
15763 Task N6 finished and destroyed. Free mem=893 No of tasks=18
16028 Task N43 current iteration: 3
16234 Task N41 current iteration: 3
16237 Task N38 current iteration: 6
16498 Task N3 current iteration: 5
16514 Task N47 current iteration: 3
16592 Task N11 current iteration: 6
16758 Task N17 current iteration: 4
17363 Task N23 current iteration: 5
17366 Task N30 current iteration: 5
17483 Task N15 current iteration: 5
17483 Task N15 finished and destroyed. Free mem=938 No of tasks=17
17528 Task N18 current iteration: 6
17528 Task N18 finished and destroyed. Free mem=983 No of tasks=16
18079 Task N14 current iteration: 5
18144 Task N38 current iteration: 7
18149 Task N50 current iteration: 4
18152 Task N49 current iteration: 4
18379 Task N31 current iteration: 4
18947 Task N45 current iteration: 4
18949 Task N26 current iteration: 4
19194 Task N5 current iteration: 5
19490 Task N11 current iteration: 7
20051 Task N38 current iteration: 8
20070 Task N47 current iteration: 4
20141 Task N43 current iteration: 4
20457 Task N30 current iteration: 6
20597 Task N3 current iteration: 6
20700 Task N41 current iteration: 4
20700 Task N41 finished and destroyed. Free mem=1028 No of tasks=15
20703 Task N23 current iteration: 6
20931 Task N50 current iteration: 5
21002 Task N49 current iteration: 5
21376 Task N17 current iteration: 5
21958 Task N38 current iteration: 9
21958 Task N38 finished and destroyed. Free mem=1073 No of tasks=14
21998 Task N14 current iteration: 6
22388 Task N11 current iteration: 8
22495 Task N45 current iteration: 5
22738 Task N31 current iteration: 5
23548 Task N30 current iteration: 7
23626 Task N47 current iteration: 5
23713 Task N50 current iteration: 6
23731 Task N26 current iteration: 5
23817 Task N5 current iteration: 6
23852 Task N49 current iteration: 6
24043 Task N23 current iteration: 7
24254 Task N43 current iteration: 5
24696 Task N3 current iteration: 7
25286 Task N11 current iteration: 9
25286 Task N11 finished and destroyed. Free mem=1118 No of tasks=13
25917 Task N14 current iteration: 7
25917 Task N14 finished and destroyed. Free mem=1163 No of tasks=12
25994 Task N17 current iteration: 6
26043 Task N45 current iteration: 6
26496 Task N50 current iteration: 7
26639 Task N30 current iteration: 8
26702 Task N49 current iteration: 7
27097 Task N31 current iteration: 6
27182 Task N47 current iteration: 6
27383 Task N23 current iteration: 8
27383 Task N23 finished and destroyed. Free mem=1208 No of tasks=11
28367 Task N43 current iteration: 6
28367 Task N43 finished and destroyed. Free mem=1253 No of tasks=10
28440 Task N5 current iteration: 7
28440 Task N5 finished and destroyed. Free mem=1298 No of tasks=9
28513 Task N26 current iteration: 6
28795 Task N3 current iteration: 8
29277 Task N50 current iteration: 8
29552 Task N49 current iteration: 8
29591 Task N45 current iteration: 7
29730 Task N30 current iteration: 9
29730 Task N30 finished and destroyed. Free mem=1343 No of tasks=8
30612 Task N17 current iteration: 7
30738 Task N47 current iteration: 7
31456 Task N31 current iteration: 7
32059 Task N50 current iteration: 9
32402 Task N49 current iteration: 9
32402 Task N49 finished and destroyed. Free mem=1388 No of tasks=7
32894 Task N3 current iteration: 9
32894 Task N3 finished and destroyed. Free mem=1433 No of tasks=6
33139 Task N45 current iteration: 8
33295 Task N26 current iteration: 7
34294 Task N47 current iteration: 8
34841 Task N50 current iteration: 10
34841 Task N50 finished and destroyed. Free mem=1478 No of tasks=5
35230 Task N17 current iteration: 8
35815 Task N31 current iteration: 8
36687 Task N45 current iteration: 9
37850 Task N47 current iteration: 9
37850 Task N47 finished and destroyed. Free mem=1523 No of tasks=4
38077 Task N26 current iteration: 8
39848 Task N17 current iteration: 9
40174 Task N31 current iteration: 9
40174 Task N31 finished and destroyed. Free mem=1568 No of tasks=3
40235 Task N45 current iteration: 10
40235 Task N45 finished and destroyed. Free mem=1613 No of tasks=2
42859 Task N26 current iteration: 9
44466 Task N17 current iteration: 10
44466 Task N17 finished and destroyed. Free mem=1658 No of tasks=1
47641 Task N26 current iteration: 10
47641 Task N26 finished and destroyed. Free mem=1703 No of tasks=0
*/

View file

@ -0,0 +1,185 @@
/**
This is example 5 rewritten with Timeout, LTS, WDT functioanlity + multitab and extra classes
- 1 second timeout is set for the main calculation task
- LTS is used to address task-specific sensor class object
- WDT is used to set the Task ID and use that for identifying the tasks (debug)
Original description:
====================
This test emulates querying 1 to 10 sensors once every 10 seconds, each could respond with a different delay
(ultrasonic sensors for instance) and printing a max value of them when all 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 distance value.
Task and SuperSensor objects are dynamically created and destroyed as needed every 10 seconds
*/
// #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
#define _TASK_PRIORITY // Support for layered scheduling priority
// #define _TASK_MICRO_RES // Support for microsecond resolution
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 and ESP32 ONLY)
#define _TASK_DEBUG // Make all methods and variables public for debug purposes
#define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
#define _TASK_TIMEOUT // Support for overall task timeout
#include <TaskScheduler.h>
#include "SuperSensor.h"
StatusRequest measure;
Scheduler ts, hts;
// Callback methods prototypes
void CycleCallback();
void CalcCallback();
bool CalcEnable();
void CalcDisable();
void SCallback();
bool SEnable();
void SDisable();
// Tasks
Task tCycle(10000, TASK_FOREVER, &CycleCallback, &hts);
Task tCalculate(TASK_IMMEDIATE , TASK_ONCE, &CalcCallback, &hts, false, &CalcEnable, &CalcDisable);
int numberSensors;
long distance;
int pins[] = { 1, 9, 3, 7, 5, 6, 4, 8, 2, 10 };
void CycleCallback() {
Serial.println();Serial.println();Serial.println();
Serial.print(millis()); Serial.print(":\t");
Serial.println("CycleCallback: Initiating measurement cycle every 10 seconds");
Serial.print("Number of sensors=");
numberSensors = random(1, 11); // 1 to 10 sensors, randomly
distance = 0;
Serial.println(numberSensors);
measure.setWaiting(numberSensors); // Set the StatusRequest to wait for 3 signals.
tCalculate.waitFor(&measure);
tCalculate.setTimeout(1000 * TASK_MILLISECOND);
}
bool CalcEnable() {
Serial.print(millis()); Serial.print(":\t");
Serial.println("CalcEnable: OnEnable");
Serial.println("Activating sensors");
for (int i = 0; i < numberSensors; i++) {
Task *t = new Task(TASK_MILLISECOND, TASK_FOREVER, &SCallback, &ts, false, &SEnable, &SDisable);
SuperSensor *s = new SuperSensor( pins[i] );
t->setLtsPointer( (void*) s);
t->setId(i + 1);
s->begin();
t->restartDelayed();
}
return true;
}
void CalcDisable() {
if (tCalculate.timedOut()) {
measure.signalComplete(-1); // signal error
Serial.print(millis()); Serial.print(":\t");
Serial.println("MeasureCallback: ***** Timeout *****");
}
ts.disableAll(false); // only disable tasks in the ts scheduler
}
void CalcCallback() {
Serial.print(millis()); Serial.print(":\t");
Serial.println("CalcCallback: calculating");
if ( measure.getStatus() >= 0) { // only calculate if statusrequest ended successfully
Serial.print("CalcCallback: Max distance="); Serial.println(distance);
Serial.println();
}
}
/** Simulation code for all sensors
-------------------------------
*/
bool SEnable() {
Task &t = ts.currentTask();
int i = t.getId();
Serial.print(millis()); Serial.print(":\t");
Serial.print("SEnable: TaskID=");
Serial.println(i);
Serial.print("Triggering sensor. Delay=");
// Another way to update the distances with one codebase - use LTS pointers
SuperSensor *s = (SuperSensor*) t.getLtsPointer();
long dly = s->trigger();
Serial.println( dly );
return true;
}
void SCallback() {
Task &t = ts.currentTask();
SuperSensor *s = (SuperSensor*) t.getLtsPointer();
if ( s->measurementReady() ) {
int i = t.getId();
Serial.print(millis()); Serial.print(":\t");
Serial.print("SCallback: TaskID=");
Serial.println(i);
Serial.print("Emulating measurement. d=");
long d = s->value();
if ( d > distance ) distance = d;
Serial.println(d);
measure.signal();
t.disable();
}
}
void SDisable() {
Task &t = ts.currentTask();
int i = t.getId();
Serial.print(millis()); Serial.print(":\t");
Serial.print("SDisable: TaskID=");
Serial.println(i);
SuperSensor *s = (SuperSensor*) ts.currentLts();
s->stop();
delete s;
delete &t;
}
/** 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(A0) + millis());
ts.setHighPriorityScheduler(&hts);
tCalculate.setTimeout(1 * TASK_SECOND);
tCycle.enable();
}
void loop() {
ts.execute();
}

View file

@ -0,0 +1,36 @@
#include "SuperSensor.h"
SuperSensor::SuperSensor(int aPin) {
iPin = aPin;
}
SuperSensor::~SuperSensor() {
iValue = -1;
}
void SuperSensor::begin() {
iDelay = random(300, 1500);
iValue = -1;
}
void SuperSensor::stop() {
//nothing to do
}
long SuperSensor::trigger() {
iStart = millis();
return iDelay;
}
bool SuperSensor::measurementReady() {
if ( millis() - iStart > iDelay ) {
iValue = random(501);
return true;
}
return false;
}
long SuperSensor::value() {
return iValue;
}

View file

@ -0,0 +1,25 @@
#ifndef _SUPER_SENSOR_H
#define _SUPER_SENSOR_H
#include "Arduino.h"
#include <TaskSchedulerDeclarations.h>
class SuperSensor {
public:
SuperSensor(int aPin);
~SuperSensor();
void begin();
void stop();
long trigger();
bool measurementReady();
long value();
private:
long iDelay;
long iValue;
int iPin;
unsigned long iStart;
};
#endif // _SUPER_SENSOR_H

View file

@ -0,0 +1,66 @@
#include "Calculator.h"
#include "SuperSensor.h"
#if defined (ARDUINO_ARCH_AVR)
#include <MemoryFree.h>
#endif
#if defined(__arm__)
extern "C" char* sbrk(int incr);
static int freeMemory() {
char top = 't';
return &top - reinterpret_cast<char*>(sbrk(0));
}
#endif
Calculator::Calculator( Scheduler* aS, Scheduler* aSensors) : Task(aS) {
iS = aSensors;
setTimeout(1000 * TASK_MILLISECOND);
}
bool Calculator::Callback() {
Serial.print(millis()); Serial.print(":\t");
Serial.println("CalcCallback: calculating");
if ( getStatusRequest()->getStatus() >= 0) { // only calculate if statusrequest ended successfully
Serial.print("CalcCallback: Max distance="); Serial.println(distance);
}
return false;
}
extern int pins[];
bool Calculator::OnEnable() {
Serial.print(millis()); Serial.print(":\t");
Serial.println("CalcEnable: OnEnable");
Serial.println("Activating sensors");
StatusRequest* sr = getStatusRequest();
iNS = sr->getCount();
distance = 0;
for (int i = 0; i < iNS; i++) {
SuperSensor *s = new SuperSensor( iS, pins[i], this, sr);
s->setId(i + 1);
s->begin();
s->restartDelayed();
}
return true;
}
void Calculator::OnDisable() {
if ( timedOut() ) {
getStatusRequest()->signalComplete(-1); // signal error
Serial.print(millis()); Serial.print(":\t");
Serial.println("MeasureCallback: ***** Timeout *****");
}
iS->disableAll(false); // only disable tasks in the ts scheduler
#if defined (ARDUINO_ARCH_AVR) || defined(__arm__)
Serial.print("Free mem = "); Serial.println(freeMemory()); Serial.println();
#endif
}
void Calculator::reportDistance(long aD) {
if (distance < aD) distance = aD;
}

View file

@ -0,0 +1,34 @@
#ifndef _CALCULATOR_H
#define _CALCULATOR_H
#include "Arduino.h"
#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_PRIORITY // Support for layered scheduling priority
#define _TASK_TIMEOUT // Support for overall task timeout
#define _TASK_OO_CALLBACKS // Support for dynamic callback method binding
#include <TaskSchedulerDeclarations.h>
class Calculator : public Task {
public:
Calculator( Scheduler* aS, Scheduler* aSensors);
void reportDistance(long aD);
bool Callback();
bool OnEnable();
void OnDisable();
private:
Scheduler* iS;
long distance;
int iNS;
};
#endif // _CALCULATOR_H

View file

@ -0,0 +1,76 @@
/**
This is example 5 rewritten with dynamic binding of callback methods
- 1 second timeout is set for the main calculation task
- LTS is used to address task-specific sensor class object
- WDT is used to set the Task ID and use that for identifying the tasks (debug)
Original description:
====================
This test emulates querying 1 to 10 sensors once every 10 seconds, each could respond with a different delay
(ultrasonic sensors for instance) and printing a max value of them when all 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 distance value.
Task and SuperSensor objects are dynamically created and destroyed as needed every 10 seconds
This sketch uses a FreeMemory library: https://github.com/McNeight/MemoryFree
FreeMemory for ARM32 boards is based on: http://www.stm32duino.com/viewtopic.php?f=18&t=2065
*/
#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_PRIORITY // Support for layered scheduling priority
#define _TASK_TIMEOUT // Support for overall task timeout
#define _TASK_OO_CALLBACKS
#include <TaskScheduler.h>
#include "SuperSensor.h"
#include "Calculator.h"
#include "Ticker.h"
StatusRequest measure;
Scheduler ts, hts;
// Tasks
Calculator* tCalculate;
Ticker* tCycle;
int pins[] = { 1, 9, 3, 7, 5, 6, 4, 8, 2, 10 };
#ifdef ARDUINO_ARCH_STM32F1
#define A0 3
#endif
/** Main Arduino code
Not much is left here - everything is taken care of by the framework
*/
void setup() {
Serial.begin(115200);
delay(1000);
while (!Serial) {}
Serial.println("TaskScheduler StatusRequest Sensor Emulation Test. Complex Test.");
#ifdef ARDUINO_ARCH_STM32F1
pinMode(A0, INPUT_ANALOG);
#endif
randomSeed(analogRead(A0) + millis());
ts.setHighPriorityScheduler(&hts);
tCalculate = new Calculator (&hts, &ts);
tCycle = new Ticker (&hts, (Task*) tCalculate, &measure);
tCalculate->setTimeout(1 * TASK_SECOND);
tCycle->enable();
}
void loop() {
ts.execute();
}

View file

@ -0,0 +1,83 @@
#include "SuperSensor.h"
SuperSensor::SuperSensor(Scheduler* aScheduler, int aPin, Calculator* aC, StatusRequest* aS) : Task(TASK_MILLISECOND, TASK_FOREVER, aScheduler, false) {
iPin = aPin;
iC = aC;
iS = aS;
}
SuperSensor::~SuperSensor() {
iValue = -1;
}
void SuperSensor::begin() {
iDelay = random(300, 1500);
iValue = -1;
}
void SuperSensor::stop() {
//nothing to do
}
long SuperSensor::trigger() {
iStart = millis();
return iDelay;
}
bool SuperSensor::measurementReady() {
if ( millis() - iStart > iDelay ) {
iValue = random(501);
return true;
}
return false;
}
long SuperSensor::value() {
return iValue;
}
bool SuperSensor::OnEnable() {
int i = getId();
Serial.print(millis()); Serial.print(":\t");
Serial.print("SEnable: TaskID=");
Serial.println(i);
Serial.print("Triggering sensor. Delay=");
long dly = trigger();
Serial.println( dly );
return true;
}
bool SuperSensor::Callback() {
if ( measurementReady() ) {
int i = getId();
Serial.print(millis()); Serial.print(":\t");
Serial.print("SCallback: TaskID=");
Serial.println(i);
Serial.print("Emulating measurement. d=");
long d = value();
iC->reportDistance(d);
Serial.println(d);
iS->signal();
disable();
delete this;
return true;
}
return false;
}
void SuperSensor::OnDisable() {
int i = getId();
Serial.print(millis()); Serial.print(":\t");
Serial.print("SDisable: TaskID=");
Serial.println(i);
stop();
}

View file

@ -0,0 +1,44 @@
#ifndef _SUPER_SENSOR_H
#define _SUPER_SENSOR_H
#include "Arduino.h"
#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_PRIORITY // Support for layered scheduling priority
#define _TASK_TIMEOUT // Support for overall task timeout
#define _TASK_OO_CALLBACKS
#include <TaskSchedulerDeclarations.h>
#include "Calculator.h"
//class Calculator;
class SuperSensor : public Task {
public:
SuperSensor(Scheduler* aScheduler, int aPin, Calculator* aC, StatusRequest* aS);
~SuperSensor();
void begin();
void stop();
long trigger();
bool measurementReady();
long value();
bool Callback();
bool OnEnable();
void OnDisable();
private:
long iDelay;
long iValue;
int iPin;
unsigned long iStart;
Calculator* iC;
StatusRequest* iS;
};
#endif // _SUPER_SENSOR_H

View file

@ -0,0 +1,20 @@
#include "Ticker.h"
Ticker::Ticker(Scheduler* aS, Task* aCalc, StatusRequest* aM) : Task(10000, TASK_FOREVER, aS, false) {
iCalc = aCalc;
iMeasure = aM;
}
bool Ticker::Callback() {
Serial.println(); Serial.println(); Serial.println();
Serial.print(millis()); Serial.print(":\t");
Serial.println("CycleCallback: Initiating measurement cycle every 10 seconds");
int numberSensors = random(1, 11); // 1 to 10 sensors, randomly
Serial.print("Number of sensors=");
Serial.println(numberSensors);
iMeasure->setWaiting(numberSensors); // Set the StatusRequest to wait for 1 to 10 signals.
iCalc->waitFor(iMeasure);
}

View file

@ -0,0 +1,28 @@
#ifndef _TICKER_H
#define _TICKER_H
#include "Arduino.h"
#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_PRIORITY // Support for layered scheduling priority
#define _TASK_TIMEOUT // Support for overall task timeout
#define _TASK_OO_CALLBACKS
#include <TaskSchedulerDeclarations.h>
class Ticker : public Task {
public:
Ticker(Scheduler* aS, Task* aCalc, StatusRequest* aM);
~Ticker() {};
bool Callback();
private:
Task *iCalc;
StatusRequest* iMeasure;
};
#endif

View file

@ -0,0 +1,78 @@
// #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
// #define _TASK_PRIORITY // Support for layered scheduling priority
// #define _TASK_MICRO_RES // Support for microsecond resolution
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 and ESP32 ONLY)
// #define _TASK_DEBUG // Make all methods and variables public for debug purposes
// #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
// #define _TASK_TIMEOUT // Support for overall task timeout
// #define _TASK_OO_CALLBACKS // Support for dynamic callback method binding
#include <TaskScheduler.h>
// Debug and Test options
#define _DEBUG_
//#define _TEST_
#ifdef _DEBUG_
#define _PP(a) Serial.print(a);
#define _PL(a) Serial.println(a);
#else
#define _PP(a)
#define _PL(a)
#endif
// Scheduler
Scheduler ts;
void task1Callback();
void task2Callback();
/*
Scheduling defines:
TASK_MILLISECOND
TASK_SECOND
TASK_MINUTE
TASK_HOUR
TASK_IMMEDIATE
TASK_FOREVER
TASK_ONCE
TASK_NOTIMEOUT
*/
Task t1 (100 * TASK_MILLISECOND, TASK_FOREVER, &task1Callback, &ts, true);
Task t2 (TASK_IMMEDIATE, 100, &task2Callback, &ts, true);
void setup() {
// put your setup code here, to run once:
#if defined(_DEBUG_) || defined(_TEST_)
Serial.begin(115200);
delay(2000);
_PL("Scheduler Template: setup()");
#endif
}
void loop() {
ts.execute();
}
void task1Callback() {
_PP(millis());
_PL(": task1Callback()");
}
void task2Callback() {
_PP(millis());
_PL(": task2Callb()");
}