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,27 @@
Copyright (c) 2015, Anatoli Arkhipenko.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,211 @@
Task Scheduler cooperative multitasking for Arduino and ESP8266 microcontrollers
Version 3.0.2 2018-11-14
If you find TaskScheduler useful for your Arduino project, please drop me an email: arkhipenko@hotmail.com
----------------------------------------------------------------------------------------------------------
OVERVIEW:
A lightweight implementation of cooperative multitasking (task scheduling) supporting:
1. Periodic task execution (with dynamic execution period in milliseconds or microseconds)
2. Number of iterations (n times)
3. Execution of tasks in predefined sequence
4. Dynamic change of task execution parameters (frequency, number of iterations, callback function)
5. Power saving via entering IDLE sleep mode between tasks are scheduled to run
6. Task invocation via Status Request object
7. Task IDs and Control Points for error handling and watchdog timer
8. Local Task Storage pointer (allowing use of same callback code for multiple tasks)
9. Layered task prioritization
10. Support for std::functions (ESP8266 only)
11. Overall task timeout
12. Static and dynamic callback method binding
13. Support for STM32F1 ARM Cortex-M3 boards
Scheduling overhead: between 15 and 18 microseconds per scheduling pass (check the benchmark example).
Tested on the following microcontrollers:
- Arduino Uno R3
- Arduino Nano
- Arduino Micro
- ATtiny85
- ESP8266 (Node MCU v2.0)
- ESP32
- Teensy (tested on Teensy 3.5)
- STM32F1 (tested on Mini USB STM32F103RCBT6 ARM Cortex-M3 leaflabs Leaf maple mini module F)
For detailed functionality overview please refer to TaskScheduler documentation in the 'extras' folder.
=======================================================================================================
Check out what TaskScheduler can do:
====================================
Endeavor - build a space capable craft, with the ability to maneuver both in and out of atmosphere.
(by Radical Space Technologies
http://radicalspacetechnologies.com/2015/10/01/endeavor-phase-i/
"So after some digging I found TaskScheduler an awesome little library developed by Anatoli Arkhipenko,
his github is here and the documentation is here. Its fantastic, so far Ive been able to replicate
some things Ive seen in Ardupilot. ..."
link: http://radicalspacetechnologies.com/2015/10/25/endeavors-code-definitely-progress/
3 Devo - Quality 3D printing filament, now made accessible and affordable
http://3devo.eu/ (http://3devo.eu/license-information/)
Houston midi clock project - TaskScheduler with microseconds resolution
(by chaffneue: My first arduino project. It's a multi-master midi controller with a shared clock and
auto count in behaviour. Project files on github: https://github.com/chaffneue/houston
youtube: https://www.youtube.com/watch?v=QRof550TtXo)
Hackabot Nano - Compact Plug and Play Arduino compatible robotic kit
(by Funnyvale: http://hackarobot.com/
also: https://www.kickstarter.com/projects/hackarobot/hackabot-nano-compact-plug-and-play-arduino-robot)
Arduino Nano based Hexbug Scarab Robotic Spider
(by arkhipenko: http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider/)
Wave your hand to control OWI Robotic Arm... no strings attached
(by arkhipenko: http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/)
APIS - Automated Plant Irrigation System
(by arkhipenko: http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/)
IoT APIS v2 - Autonomous IoT-enabled Automated Plant Irrigation System
(by arkhipenko: http://www.instructables.com/id/IoT-APIS-V2-Autonomous-IoT-enabled-Automated-Plant/)
Interactive Halloween Pumpkin
(by arkhipenko: http://www.instructables.com/id/Interactive-Halloween-Pumpkin/)
Changelog:
=========
v3.0.0: MAJOR RELEASE
2018-03-15 - Optional Dynamic callback method binding (_TASK_OO_CALLBACKS compilation directive).
v2.6.1:
2018-02-13 - Bug: Support for task self-destruction in the OnDisable method.
Example 19: dynamic task creation and destruction.
2018-03-14 - Bug: high level scheduler ignored if lower level chain is empty
Example 20: use of local task storage to work with task-specific class objects
v2.6.0:
2018-01-30 - _TASK_TIMEOUT compilation directive: Task overall timeout functionality
2018-01-30 - Support for ESP32
(Contributed by Marco Tombesi: https://github.com/baggior)
v2.5.2:
2018-01-09 - _TASK_INLINE compilation directive making all methods declared "inline" (issue #42)
v2.5.1:
2018-01-06 - support for IDLE sleep on Teensy boards (tested on Teensy 3.6)
v2.5.0:
2017-04-27 - added optional support for std::functions via _TASK_STD_FUNCTION
(Contributed by Edwin van Leeuwen [BlackEdder - https://github.com/BlackEdder)
2017-08-30 - add _TASK_DEBUG making all methods and variables public FOR DEBUGGING PURPOSES ONLY!
*** USE AT YOUR OWN RISK ***
2017-08-30 - bug fix: Scheduler::addTask() checks if task is already part of an execution chain (github issue #37)
2017-08-30 - support for multi-tab sketches (Contributed by Adam Ryczkowski - https://github.com/adamryczkowski)
v2.4.0:
2017-04-27 - added destructor to the Task class to ensure tasks are disables and taken off the execution chain
upon destruction. (Contributed by Edwin van Leeuwen [BlackEdder - https://github.com/BlackEdder)
v2.3.0:
2017-02-24 - new timeUntilNextIteration() method within Scheduler class - inquire when a particlar task is
scheduled to run next time
v2.2.1:
2016-11-30 - inlined constructors. Added "yield()" and "yieldOnce()" functions to easily break down and
chain back together long running callback methods
2016-12-16 - added "getCount()" to StatusRequest objects, made every task StatusRequest enabled.
Internal StatusRequest objects are accessible via "getInternalStatusRequest()" method.
v2.2.0:
2016-11-17 - all methods made 'inline' to support inclusion of TaskSchedule.h file into other header files
v2.1.0:
2016-02-01 - support for microsecond resolution
2016-02-02 - added Scheduler baseline start time reset method: startNow()
v2.0.1:
2016-01-02 - bug fix: issue#11 Xtensa compiler (esp8266): Declaration of constructor does not match implementation
v2.0.0:
2015-12-22 - _TASK_PRIORITY - support for layered task prioritization
v1.9.2:
2015-11-28 - _TASK_ROLLOVER_FIX is deprecated (not necessary)
2015-12-16 - bug fixes: automatic millis rollover support for delay methods
2015-12-17 - new method for _TASK_TIMECRITICAL option: getStartDelay()
v1.9.0:
2015-11-24 - packed three byte-long status variables into one byte-long bit array structure data type - saving 2 bytes per each task instance
v1.8.5:
2015-11-23 - bug fix: incorrect calculation of next task invocation in case callback changed the interval
2015-11-23 - bug fix: Task::set() method calls setInterval() explicitly, therefore delaying the task in the same manner
v1.8.4:
2015-11-15 - bug fix: Task alignment with millis() for scheduling purposes should be done after OnEnable, not before. Especially since OnEnable method can change the interval
v1.8.3:
2015-11-05 - support for task activation on a status request with arbitrary interval and number of iterations (0 and 1 are still default values)
2015-11-05 - implement waitForDelayed() method to allow task activation on the status request completion delayed for one current interval
2015-11-09 - added callback methods prototypes to all examples for Arduino IDE 1.6.6 compatibility
2015-11-14 - added several constants to be used as task parameters for readability (e.g, TASK_FOREVER, TASK_SECOND, etc.)
2015-11-14 - significant optimization of the scheduler's execute loop, including millis() rollover fix option
v1.8.2:
2015-10-27 - implement Local Task Storage Pointer (allow use of same callback code for different tasks)
2015-10-27 - bug: currentTask() method returns incorrect Task reference if called within OnEnable and OnDisable methods
2015-10-27 - protection against infinite loop in OnEnable (if enable() methods are called within OnEnable)
2015-10-29 - new currentLts() method in the scheduler class returns current task's LTS pointer in one call
v1.8.1:
2015-10-22 - implement Task id and control points to support identification of failure points for watchdog timer logging
v1.8.0:
2015-10-13 - support for status request objects allowing tasks waiting on requests
2015-10-13 - moved to a single header file to allow compilation control via #defines from the main sketch
v1.7.0:
2015-10-08 - introduced callback run counter - callback functions can branch on the iteration number.
2015-10-11 - enableIfNot() - enable a task only if it is not already enabled. Returns true if was already enabled, false if was disabled.
2015-10-11 - disable() returns previous enable state (true if was enabled, false if was already disabled)
2015-10-11 - introduced callback functions "on enable" and "on disable". On enable runs every time enable is called, on disable runs only if task was enabled
2015-10-12 - new Task method: forceNextIteration() - makes next iteration happen immediately during the next pass regardless how much time is left
v1.6.0:
2015-09-22 - revert back to having all tasks disable on last iteration.
2015-09-22 - deprecated disableOnLastIteration method as a result
2015-10-01 - made version numbers semver compliant (documentation only)
v1.5.1:
2015-09-21 - bug fix: incorrect handling of active tasks via set() and setIterations().
Thanks to Hannes Morgenstern for catching this one
v1.5.0:
2015-09-20 - access to currently executing task (for callback functions)
2015-09-20 - pass scheduler as a parameter to the task constructor to append the task to the end of the chain
2015-09-20 - option to create a task already enabled
v1.4.1:
2015-09-15 - more careful placement of AVR-specific includes for sleep functions (compatibility with DUE)
sleep on idle run is no longer a default and should be explicitly compiled with _TASK_SLEEP_ON_IDLE_RUN defined
v1.0.0:
2015-02-24 - Initial release
2015-02-28 - added delay() and disableOnLastIteration() functions
2015-03-25 - changed scheduler execute() function for a more precise delay calculation:
1. Do not delay if any of the tasks ran (making request for immediate execution redundant)
2. Delay is invoked only if none of the tasks ran
3. Delay is based on the min anticipated wait until next task _AND_ the runtime of execute function itself.
2015-05-11 - added restart() and restartDelayed() functions to restart tasks which are on hold after running all iterations
2015-05-19 - completely removed delay from the scheduler since there are no power saving there. using 1 ms sleep instead

View file

@ -0,0 +1,77 @@
# Task Scheduler
### Cooperative multitasking for Arduino microcontrollers
#### Version 3.0.2: 2018-11-14
### OVERVIEW:
A lightweight implementation of cooperative multitasking (task scheduling) supporting:
1. Periodic task execution, with dynamic execution period in `milliseconds` (default) or `microseconds` (if explicitly enabled) frequency of execution
2. Number of iterations (limited or infinite number of iterations)
3. Execution of tasks in predefined sequence
4. Dynamic change of task execution parameters (frequency, number of iterations, callback methods)
5. Power saving via entering **IDLE** sleep mode when tasks are not scheduled to run
6. Support for event-driven task invocation via Status Request object
7. Support for task IDs and Control Points for error handling and watchdog timer
8. Support for Local Task Storage pointer (allowing use of same callback code for multiple tasks)
9. Support for layered task prioritization
10. Support for `std::functions` (`ESP8266` only)
11. Overall task timeout
12. Static and dynamic callback method binding
13. Support for STM32F1 ARM Cortex-M3 boards
Scheduling overhead: between `15` and `18` microseconds per scheduling pass (Arduino UNO rev 3 @ `16MHz` clock, single scheduler w/o prioritization)
**TaskScheduler** was tested on the following platforms:
* Arduino Uno R3
* Arduino Nano
* Arduino Micro
* ATtiny85
* ESP8266 (Node MCU v2.0)
* ESP32
* Teensy (tested on Teensy 3.5)
* STM32F1 (tested on Mini USB STM32F103RCBT6 ARM Cortex-M3 leaflabs Leaf maple mini module F)
---
![TaskScheduler process diagram](https://github.com/arkhipenko/TaskScheduler/raw/master/extras/TaskScheduler_html.png)
---
### Changelog is located [here.](https://github.com/arkhipenko/TaskScheduler/wiki/Changelog)
#### For detailed functionality overview please refer to TaskScheduler documentation in the 'extras' folder or in the [Wiki page](https://github.com/arkhipenko/TaskScheduler/wiki).
### Check out what TaskScheduler can do:
* [3 Devo](http://3devo.eu/) - Quality 3D printing filament, now made accessible and affordable
(http://3devo.eu/license-information/)
* [Houston midi](https://github.com/chaffneue/houston) clock project - TaskScheduler with microseconds resolution
>by chaffneue:
>>My first arduino project. It's a multi-master midi controller with a shared clock and
auto count in behaviour.
youtube: https://www.youtube.com/watch?v=QRof550TtXo
* [Hackabot Nano](http://hackarobot.com/) by Funnyvale - Compact Plug and Play Arduino compatible robotic kit
https://www.kickstarter.com/projects/hackarobot/hackabot-nano-compact-plug-and-play-arduino-robot
* Arduino Nano based Hexbug Scarab Robotic Spider
(by arkhipenko: http://www.instructables.com/id/Arduino-Nano-based-Hexbug-Scarab-Robotic-Spider/)
* Wave your hand to control OWI Robotic Arm... no strings attached
(by arkhipenko: http://www.instructables.com/id/Wave-your-hand-to-control-OWI-Robotic-Arm-no-strin/)
* APIS - Automated Plant Irrigation System
(by arkhipenko: http://www.instructables.com/id/APIS-Automated-Plant-Irrigation-System/)
* IoT APIS v2 - Autonomous IoT-enabled Automated Plant Irrigation System
(by arkhipenko: http://www.instructables.com/id/IoT-APIS-V2-Autonomous-IoT-enabled-Automated-Plant/)
* Interactive Halloween Pumpkin
(by arkhipenko: http://www.instructables.com/id/Interactive-Halloween-Pumpkin/)
* Interactive Predator Costume with Real-Time Head Tracking Plasma Cannon
(by arkhipenko: https://www.instructables.com/id/Interactive-Predator-Costume-With-Head-Tracking-Pl/)

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()");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View file

@ -0,0 +1,108 @@
#######################################
# Syntax Coloring Map For TaskManager
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Task KEYWORD1
Scheduler KEYWORD1
StatusRequest KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
init KEYWORD2
addTask KEYWORD2
deleteTask KEYWORD2
disableAll KEYWORD2
enableAll KEYWORD2
currentTask KEYWORD2
currentLts KEYWORD2
execute KEYWORD2
timeUntilNextIteration KEYWORD2
startNow KEYWORD2
allowSleep KEYWORD2
enable KEYWORD2
enableIfNot KEYWORD2
enableDelayed KEYWORD2
delay KEYWORD2
forceNextIteration KEYWORD2
restart KEYWORD2
restartDelayed KEYWORD2
disable KEYWORD2
isEnabled KEYWORD2
set KEYWORD2
setInterval KEYWORD2
getInterval KEYWORD2
setIterations KEYWORD2
getIterations KEYWORD2
getRunCounter KEYWORD2
setCallback KEYWORD2
setOnEnable KEYWORD2
setOnDisable KEYWORD2
disableOnLastIteration KEYWORD2
yield KEYWORD2
yieldOnce KEYWORD2
getInternalStatusRequest KEYWORD2
getCount KEYWORD2
getOverrun KEYWORD2
getStartDelay KEYWORD2
isFirstIteration KEYWORD2
isLastIteration KEYWORD2
setWaiting KEYWORD2
signal KEYWORD2
signalComplete KEYWORD2
pending KEYWORD2
completed KEYWORD2
getStatus KEYWORD2
waitFor KEYWORD2
waitForDelayed KEYWORD2
getStatusRequest KEYWORD2
getCount KEYWORD2
setId KEYWORD2
getId KEYWORD2
setControlPoint KEYWORD2
getControlPoint KEYWORD2
setLtsPointer KEYWORD2
getLtsPointer KEYWORD2
isOverrun KEYWORD2
setHighPriorityScheduler KEYWORD2
currentScheduler KEYWORD2
setTimeout KEYWORD2
resetTimeout KEYWORD2
getTimeout KEYWORD2
untilTimeout KEYWORD2
timedOut KEYWORD2
Callback KEYWORD2
OnEnable KEYWORD2
OnDisable KEYWORD2
#######################################
# Constants (LITERAL1)
TASK_MILLISECOND LITERAL1
TASK_SECOND LITERAL1
TASK_MINUTE LITERAL1
TASK_HOUR LITERAL1
TASK_FOREVER LITERAL1
TASK_IMMEDIATE LITERAL1
TASK_ONCE LITERAL1
TASK_NOTIMEOUT LITERAL1
_TASK_TIMECRITICAL LITERAL1
_TASK_SLEEP_ON_IDLE_RUN LITERAL1
_TASK_STATUS_REQUEST LITERAL1
_TASK_WDT_IDS LITERAL1
_TASK_LTS_POINTER LITERAL1
_TASK_PRIORITY LITERAL1
_TASK_MICRO_RES LITERAL1
_TASK_STD_FUNCTION LITERAL1
_TASK_DEBUG LITERAL1
_TASK_INLINE LITERAL1
_TASK_TIMEOUT LITERAL1
_TASK_OO_CALLBACKS LITERAL1
TaskCallback LITERAL1
TaskOnDisable LITERAL1
TaskOnEnable LITERAL1
#######################################

View file

@ -0,0 +1,22 @@
{
"name": "TaskScheduler",
"keywords": "multitasking, cooperative, event, task, taskscheduler, scheduling",
"description": "Cooperative multitasking for Arduino and ESP8266 microcontrollers",
"repository":
{
"type": "git",
"url": "https://github.com/arkhipenko/TaskScheduler"
},
"authors":
[
{
"name": "Anatoli Arkhipenko",
"email": "arkhipenko@hotmail.com",
"url": "https://github.com/arkhipenko",
"maintainer": true
}
],
"version": "3.0.2",
"frameworks": "arduino",
"platforms": "*"
}

View file

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,309 @@
// Cooperative multitasking library for Arduino
// Copyright (c) 2015-2017 Anatoli Arkhipenko
#include <stddef.h>
#include <stdint.h>
#ifndef _TASKSCHEDULERDECLARATIONS_H_
#define _TASKSCHEDULERDECLARATIONS_H_
// ----------------------------------------
// The following "defines" control library functionality at compile time,
// and should be used in the main sketch depending on the functionality required
//
// #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
// #define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between tasks if no callback 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
#ifdef _TASK_DEBUG
#define _TASK_SCOPE public
#else
#define _TASK_SCOPE private
#endif
#define TASK_IMMEDIATE 0
#define TASK_FOREVER (-1)
#define TASK_ONCE 1
#ifdef _TASK_TIMEOUT
#define TASK_NOTIMEOUT 0
#endif
#ifdef _TASK_PRIORITY
class Scheduler;
extern Scheduler* iCurrentScheduler;
#endif // _TASK_PRIORITY
#if !defined(ARDUINO)
extern unsigned long micros(void);
extern unsigned long millis(void);
#endif
#ifdef _TASK_INLINE
#define INLINE inline
#else
#define INLINE
#endif
#ifndef _TASK_MICRO_RES
#define TASK_MILLISECOND 1UL
#define TASK_SECOND 1000UL
#define TASK_MINUTE 60000UL
#define TASK_HOUR 3600000UL
#else
#define TASK_MILLISECOND 1000UL
#define TASK_SECOND 1000000UL
#define TASK_MINUTE 60000000UL
#define TASK_HOUR 3600000000UL
#endif // _TASK_MICRO_RES
#ifdef _TASK_STATUS_REQUEST
#define _TASK_SR_NODELAY 1
#define _TASK_SR_DELAY 2
class StatusRequest {
public:
INLINE StatusRequest();
INLINE void setWaiting(unsigned int aCount = 1);
INLINE bool signal(int aStatus = 0);
INLINE void signalComplete(int aStatus = 0);
INLINE bool pending();
INLINE bool completed();
INLINE int getStatus();
INLINE int getCount();
_TASK_SCOPE:
unsigned int iCount; // number of statuses to wait for. waiting for more that 65000 events seems unreasonable: unsigned int should be sufficient
int iStatus; // status of the last completed request. negative = error; zero = OK; positive = OK with a specific status
};
#endif // _TASK_STATUS_REQUEST
#ifdef _TASK_STD_FUNCTION
#include <functional>
typedef std::function<void()> TaskCallback;
typedef std::function<void()> TaskOnDisable;
typedef std::function<bool()> TaskOnEnable;
#else
typedef void (*TaskCallback)();
typedef void (*TaskOnDisable)();
typedef bool (*TaskOnEnable)();
#endif
typedef struct {
bool enabled : 1; // indicates that task is enabled or not.
bool inonenable : 1; // indicates that task execution is inside OnEnable method (preventing infinite loops)
#ifdef _TASK_STATUS_REQUEST
uint8_t waiting : 2; // indication if task is waiting on the status request
#endif
#ifdef _TASK_TIMEOUT
bool timeout : 1; // indication if task is waiting on the status request
#endif
} __task_status;
class Scheduler;
class Task {
friend class Scheduler;
public:
#ifdef _TASK_OO_CALLBACKS
INLINE Task(unsigned long aInterval=0, long aIterations=0, Scheduler* aScheduler=NULL, bool aEnable=false);
#else
INLINE Task(unsigned long aInterval=0, long aIterations=0, TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, bool aEnable=false, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
#endif // _TASK_OO_CALLBACKS
#ifdef _TASK_STATUS_REQUEST
#ifdef _TASK_OO_CALLBACKS
// INLINE Task(Scheduler* aScheduler=NULL);
INLINE Task(Scheduler* aScheduler);
#else
// INLINE Task(TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
INLINE Task(TaskCallback aCallback, Scheduler* aScheduler, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
#endif // _TASK_OO_CALLBACKS
#endif // _TASK_STATUS_REQUEST
INLINE ~Task();
#ifdef _TASK_TIMEOUT
INLINE void setTimeout(unsigned long aTimeout, bool aReset=false);
INLINE void resetTimeout();
INLINE unsigned long getTimeout();
INLINE long untilTimeout();
INLINE bool timedOut();
#endif
INLINE void enable();
INLINE bool enableIfNot();
INLINE void enableDelayed(unsigned long aDelay=0);
INLINE void restart();
INLINE void restartDelayed(unsigned long aDelay=0);
INLINE void delay(unsigned long aDelay=0);
INLINE void forceNextIteration();
INLINE bool disable();
INLINE bool isEnabled();
#ifdef _TASK_OO_CALLBACKS
INLINE void set(unsigned long aInterval, long aIterations);
#else
INLINE void set(unsigned long aInterval, long aIterations, TaskCallback aCallback,TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
#endif // _TASK_OO_CALLBACKS
INLINE void setInterval(unsigned long aInterval);
INLINE unsigned long getInterval();
INLINE void setIterations(long aIterations);
INLINE long getIterations();
INLINE unsigned long getRunCounter() ;
#ifdef _TASK_OO_CALLBACKS
virtual INLINE bool Callback() =0; // return true if run was "productive - this will disable sleep on the idle run for next pass
virtual INLINE bool OnEnable(); // return true if task should be enabled, false if it should remain disabled
virtual INLINE void OnDisable();
#else
INLINE void setCallback(TaskCallback aCallback) ;
INLINE void setOnEnable(TaskOnEnable aCallback) ;
INLINE void setOnDisable(TaskOnDisable aCallback) ;
INLINE void yield(TaskCallback aCallback);
INLINE void yieldOnce(TaskCallback aCallback);
#endif // _TASK_OO_CALLBACKS
INLINE bool isFirstIteration() ;
INLINE bool isLastIteration() ;
#ifdef _TASK_TIMECRITICAL
INLINE long getOverrun() ;
INLINE long getStartDelay() ;
#endif // _TASK_TIMECRITICAL
#ifdef _TASK_STATUS_REQUEST
INLINE void waitFor(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
INLINE void waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1);
INLINE StatusRequest* getStatusRequest() ;
INLINE StatusRequest* getInternalStatusRequest() ;
#endif // _TASK_STATUS_REQUEST
#ifdef _TASK_WDT_IDS
INLINE void setId(unsigned int aID) ;
INLINE unsigned int getId() ;
INLINE void setControlPoint(unsigned int aPoint) ;
INLINE unsigned int getControlPoint() ;
#endif // _TASK_WDT_IDS
#ifdef _TASK_LTS_POINTER
INLINE void setLtsPointer(void *aPtr) ;
void* getLtsPointer() ;
#endif // _TASK_LTS_POINTER
_TASK_SCOPE:
INLINE void reset();
volatile __task_status iStatus;
volatile unsigned long iInterval; // execution interval in milliseconds (or microseconds). 0 - immediate
volatile unsigned long iDelay; // actual delay until next execution (usually equal iInterval)
volatile unsigned long iPreviousMillis; // previous invocation time (millis). Next invocation = iPreviousMillis + iInterval. Delayed tasks will "catch up"
#ifdef _TASK_TIMECRITICAL
volatile long iOverrun; // negative if task is "catching up" to it's schedule (next invocation time is already in the past)
volatile long iStartDelay; // actual execution of the task's callback method was delayed by this number of millis
#endif // _TASK_TIMECRITICAL
volatile long iIterations; // number of iterations left. 0 - last iteration. -1 - infinite iterations
long iSetIterations; // number of iterations originally requested (for restarts)
unsigned long iRunCounter; // current number of iteration (starting with 1). Resets on enable.
#ifndef _TASK_OO_CALLBACKS
TaskCallback iCallback; // pointer to the void callback method
TaskOnEnable iOnEnable; // pointer to the bool OnEnable callback method
TaskOnDisable iOnDisable; // pointer to the void OnDisable method
#endif // _TASK_OO_CALLBACKS
Task *iPrev, *iNext; // pointers to the previous and next tasks in the chain
Scheduler *iScheduler; // pointer to the current scheduler
#ifdef _TASK_STATUS_REQUEST
StatusRequest *iStatusRequest; // pointer to the status request task is or was waiting on
StatusRequest iMyStatusRequest; // internal Status request to let other tasks know of completion
#endif // _TASK_STATUS_REQUEST
#ifdef _TASK_WDT_IDS
unsigned int iTaskID; // task ID (for debugging and watchdog identification)
unsigned int iControlPoint; // current control point within the callback method. Reset to 0 by scheduler at the beginning of each pass
#endif // _TASK_WDT_IDS
#ifdef _TASK_LTS_POINTER
void *iLTS; // pointer to task's local storage. Needs to be recast to appropriate type (usually a struct).
#endif // _TASK_LTS_POINTER
#ifdef _TASK_TIMEOUT
unsigned long iTimeout; // Task overall timeout
unsigned long iStarttime; // millis at task start time
#endif // _TASK_TIMEOUT
};
class Scheduler {
friend class Task;
public:
INLINE Scheduler();
// ~Scheduler();
INLINE void init();
INLINE void addTask(Task& aTask);
INLINE void deleteTask(Task& aTask);
INLINE void disableAll(bool aRecursive = true);
INLINE void enableAll(bool aRecursive = true);
INLINE bool execute(); // Returns true if none of the tasks' callback methods was invoked (true = idle run)
INLINE void startNow(bool aRecursive = true); // reset ALL active tasks to immediate execution NOW.
INLINE Task& currentTask() ;
INLINE long timeUntilNextIteration(Task& aTask); // return number of ms until next iteration of a given Task
#ifdef _TASK_SLEEP_ON_IDLE_RUN
INLINE void allowSleep(bool aState = true);
#endif // _TASK_SLEEP_ON_IDLE_RUN
#ifdef _TASK_LTS_POINTER
INLINE void* currentLts();
#endif // _TASK_LTS_POINTER
#ifdef _TASK_TIMECRITICAL
INLINE bool isOverrun();
#endif // _TASK_TIMECRITICAL
#ifdef _TASK_PRIORITY
INLINE void setHighPriorityScheduler(Scheduler* aScheduler);
INLINE static Scheduler& currentScheduler() { return *(iCurrentScheduler); };
#endif // _TASK_PRIORITY
_TASK_SCOPE:
Task *iFirst, *iLast, *iCurrent; // pointers to first, last and current tasks in the chain
#ifdef _TASK_SLEEP_ON_IDLE_RUN
bool iAllowSleep; // indication if putting avr to IDLE_SLEEP mode is allowed by the program at this time.
#endif // _TASK_SLEEP_ON_IDLE_RUN
#ifdef _TASK_PRIORITY
Scheduler *iHighPriority; // Pointer to a higher priority scheduler
#endif // _TASK_PRIORITY
};
#endif /* _TASKSCHEDULERDECLARATIONS_H_ */