初始化提交
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
Every example set must have a LED blink example
|
||||
For this one the idea is to have as many ways to blink the LED
|
||||
as I can think of. So, here we go.
|
||||
|
||||
Tested on:
|
||||
- Arduino Nano
|
||||
- ESP8266
|
||||
- ESP32
|
||||
- STM32 Maple Mini
|
||||
*/
|
||||
|
||||
|
||||
// #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
|
||||
|
||||
// LED_BUILTIN 13
|
||||
#if defined( ARDUINO_ARCH_ESP32 )
|
||||
#define LED_BUILTIN 23 // esp32 dev2 kit does not have LED
|
||||
#endif
|
||||
|
||||
// Scheduler
|
||||
Scheduler ts;
|
||||
|
||||
/*
|
||||
Approach 1: LED is driven by the boolean variable; false = OFF, true = ON
|
||||
*/
|
||||
#define PERIOD1 500
|
||||
#define DURATION 10000
|
||||
void blink1CB();
|
||||
Task tBlink1 ( PERIOD1 * TASK_MILLISECOND, DURATION / PERIOD1, &blink1CB, &ts, true );
|
||||
|
||||
/*
|
||||
Approac 2: two callback methods: one turns ON, another turns OFF
|
||||
*/
|
||||
#define PERIOD2 400
|
||||
void blink2CB_ON();
|
||||
void blink2CB_OFF();
|
||||
Task tBlink2 ( PERIOD2 * TASK_MILLISECOND, DURATION / PERIOD2, &blink2CB_ON, &ts, false );
|
||||
|
||||
/*
|
||||
Approach 3: Use RunCounter
|
||||
*/
|
||||
#define PERIOD3 300
|
||||
void blink3CB();
|
||||
Task tBlink3 (PERIOD3 * TASK_MILLISECOND, DURATION / PERIOD3, &blink3CB, &ts, false);
|
||||
|
||||
/*
|
||||
Approach 4: Use status request objects to pass control from one task to the other
|
||||
*/
|
||||
#define PERIOD4 200
|
||||
bool blink41OE();
|
||||
void blink41();
|
||||
void blink42();
|
||||
void blink42OD();
|
||||
Task tBlink4On ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink41, &ts, false, &blink41OE );
|
||||
Task tBlink4Off ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink42, &ts, false, NULL, &blink42OD );
|
||||
|
||||
|
||||
/*
|
||||
Approach 5: Two interleaving tasks
|
||||
*/
|
||||
#define PERIOD5 600
|
||||
bool blink51OE();
|
||||
void blink51();
|
||||
void blink52();
|
||||
void blink52OD();
|
||||
Task tBlink5On ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink51, &ts, false, &blink51OE );
|
||||
Task tBlink5Off ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink52, &ts, false, NULL, &blink52OD );
|
||||
|
||||
|
||||
/*
|
||||
Approach 6: RunCounter-based with random intervals
|
||||
*/
|
||||
#define PERIOD6 300
|
||||
void blink6CB();
|
||||
bool blink6OE();
|
||||
void blink6OD();
|
||||
Task tBlink6 ( PERIOD6 * TASK_MILLISECOND, DURATION / PERIOD6, &blink6CB, &ts, false, &blink6OE, &blink6OD );
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
#if defined(_DEBUG_) || defined(_TEST_)
|
||||
Serial.begin(115200);
|
||||
delay(TASK_SECOND);
|
||||
_PL("TaskScheduler Blink example");
|
||||
_PL("Blinking for 10 seconds using various techniques\n");
|
||||
delay(2 * TASK_SECOND);
|
||||
#endif
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
ts.execute();
|
||||
}
|
||||
|
||||
inline void LEDOn() {
|
||||
digitalWrite( LED_BUILTIN, HIGH );
|
||||
}
|
||||
|
||||
inline void LEDOff() {
|
||||
digitalWrite( LED_BUILTIN, LOW );
|
||||
}
|
||||
|
||||
// === 1 =======================================
|
||||
bool LED_state = false;
|
||||
void blink1CB() {
|
||||
if ( tBlink1.isFirstIteration() ) {
|
||||
_PP(millis());
|
||||
_PL(": Blink1 - simple flag driven");
|
||||
LED_state = false;
|
||||
}
|
||||
|
||||
if ( LED_state ) {
|
||||
LEDOff();
|
||||
LED_state = false;
|
||||
}
|
||||
else {
|
||||
LEDOn();
|
||||
LED_state = true;
|
||||
}
|
||||
|
||||
if ( tBlink1.isLastIteration() ) {
|
||||
tBlink2.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === 2 ======================================
|
||||
void blink2CB_ON() {
|
||||
if ( tBlink2.isFirstIteration() ) {
|
||||
_PP(millis());
|
||||
_PL(": Blink2 - 2 callback methods");
|
||||
}
|
||||
|
||||
LEDOn();
|
||||
tBlink2.setCallback( &blink2CB_OFF );
|
||||
|
||||
if ( tBlink2.isLastIteration() ) {
|
||||
tBlink3.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void blink2CB_OFF() {
|
||||
|
||||
LEDOff();
|
||||
tBlink2.setCallback( &blink2CB_ON );
|
||||
|
||||
if ( tBlink2.isLastIteration() ) {
|
||||
tBlink3.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === 3 =====================================
|
||||
void blink3CB() {
|
||||
if ( tBlink3.isFirstIteration() ) {
|
||||
_PP(millis());
|
||||
_PL(": Blink3 - Run Counter driven");
|
||||
}
|
||||
|
||||
if ( tBlink3.getRunCounter() & 1 ) {
|
||||
LEDOn();
|
||||
}
|
||||
else {
|
||||
LEDOff();
|
||||
}
|
||||
|
||||
if ( tBlink3.isLastIteration() ) {
|
||||
tBlink4On.setOnEnable( &blink41OE );
|
||||
tBlink4On.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === 4 =============================================
|
||||
int counter = 0;
|
||||
bool blink41OE() {
|
||||
_PP(millis());
|
||||
_PL(": Blink4 - Internal status request based");
|
||||
counter = 0;
|
||||
tBlink4On.setOnEnable( NULL );
|
||||
return true;
|
||||
}
|
||||
|
||||
void blink41() {
|
||||
// _PP(millis());
|
||||
// _PL(": blink41");
|
||||
LEDOn();
|
||||
StatusRequest* r = tBlink4On.getInternalStatusRequest();
|
||||
tBlink4Off.waitForDelayed( r );
|
||||
counter++;
|
||||
}
|
||||
|
||||
void blink42() {
|
||||
// _PP(millis());
|
||||
// _PL(": blink42");
|
||||
LEDOff();
|
||||
StatusRequest* r = tBlink4Off.getInternalStatusRequest();
|
||||
tBlink4On.waitForDelayed( r );
|
||||
counter++;
|
||||
}
|
||||
|
||||
|
||||
void blink42OD() {
|
||||
if ( counter >= DURATION / PERIOD4 ) {
|
||||
tBlink4On.disable();
|
||||
tBlink4Off.disable();
|
||||
|
||||
tBlink5On.setOnEnable( &blink51OE );
|
||||
tBlink5On.restartDelayed( 2 * TASK_SECOND );
|
||||
tBlink5Off.restartDelayed( 2 * TASK_SECOND + PERIOD5 / 2 );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === 5 ==========================================
|
||||
bool blink51OE() {
|
||||
_PP(millis());
|
||||
_PL(": Blink5 - Two interleaving tasks");
|
||||
tBlink5On.setOnEnable( NULL );
|
||||
return true;
|
||||
}
|
||||
void blink51() {
|
||||
// _PP(millis());
|
||||
// _PL(": blink51");
|
||||
LEDOn();
|
||||
}
|
||||
void blink52() {
|
||||
// _PP(millis());
|
||||
// _PL(": blink52");
|
||||
LEDOff();
|
||||
}
|
||||
void blink52OD() {
|
||||
tBlink6.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
|
||||
|
||||
// === 6 ============================================
|
||||
long interval6 = 0;
|
||||
bool blink6OE() {
|
||||
_PP(millis());
|
||||
_PP(": Blink6 - RunCounter + Random ON interval = ");
|
||||
interval6 = random( 100, 901 );
|
||||
tBlink6.setInterval( interval6 );
|
||||
_PL( interval6 );
|
||||
tBlink6.delay( 2 * TASK_SECOND );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void blink6CB() {
|
||||
if ( tBlink6.getRunCounter() & 1 ) {
|
||||
LEDOn();
|
||||
tBlink6.setInterval( interval6 );
|
||||
}
|
||||
else {
|
||||
LEDOff();
|
||||
tBlink6.setInterval( TASK_SECOND - interval6 );
|
||||
}
|
||||
}
|
||||
|
||||
void blink6OD() {
|
||||
tBlink1.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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>.
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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>
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
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.
|
||||
Garbage collection deletes all the tasks which have finished (enabled in their respective
|
||||
OnDisable methods)
|
||||
|
||||
This sketch uses the following libraries:
|
||||
- FreeMemory library: https://github.com/McNeight/MemoryFree
|
||||
- QueueArray library: https://playground.arduino.cc/Code/QueueArray/
|
||||
*/
|
||||
|
||||
#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 <QueueArray.h>
|
||||
|
||||
#if defined (ARDUINO_ARCH_AVR)
|
||||
#include <MemoryFree.h>
|
||||
#elif defined(__arm__)
|
||||
extern "C" char* sbrk(int incr);
|
||||
static int freeMemory() {
|
||||
char top = 't';
|
||||
return &top - reinterpret_cast<char*>(sbrk(0));
|
||||
}
|
||||
#else
|
||||
int freeMemory(); // supply your own
|
||||
#endif
|
||||
|
||||
Scheduler ts;
|
||||
|
||||
// Callback methods prototypes
|
||||
void MainLoop();
|
||||
void GC();
|
||||
|
||||
// Statis task
|
||||
Task tMain(100 * TASK_MILLISECOND, 100, &MainLoop, &ts, true);
|
||||
Task tGarbageCollection(200 * TASK_MILLISECOND, TASK_FOREVER, &GC, &ts, false);
|
||||
|
||||
|
||||
void Iteration();
|
||||
bool OnEnable();
|
||||
void OnDisable();
|
||||
|
||||
int noOfTasks = 0;
|
||||
QueueArray <Task*> toDelete;
|
||||
|
||||
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();
|
||||
toDelete.push(t);
|
||||
tGarbageCollection.enableIfNot();
|
||||
|
||||
Serial.print(millis()); Serial.print("\t");
|
||||
Serial.print("Task N"); Serial.print(tid); Serial.println(F("\tfinished"));
|
||||
}
|
||||
|
||||
/**
|
||||
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 GC() {
|
||||
if ( toDelete.isEmpty() ) {
|
||||
tGarbageCollection.disable();
|
||||
return;
|
||||
}
|
||||
Task *t = toDelete.pop();
|
||||
Serial.print(millis()); Serial.print("\t");
|
||||
Serial.print("Task N"); Serial.print(t->getId()); Serial.println(F("\tdestroyed"));
|
||||
Serial.print("Free mem="); Serial.print(freeMemory());
|
||||
Serial.print(F("\tNo of tasks=")); Serial.println(--noOfTasks);
|
||||
delete t;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
ts.execute();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
An example of using scheduler's custom sleep callback method
|
||||
|
||||
An empty loop is executed for 10 seconds with a 10 ms. interval
|
||||
The first time it is excuted with an empty sleep callback, and
|
||||
the second time with a 1 ms delay in the custom callback
|
||||
|
||||
RESULTS:
|
||||
|
||||
Arduino Nano:
|
||||
=================================
|
||||
Testing empty sleep callback...
|
||||
cEmptyCallback=1001
|
||||
cEmptyTotal=423866
|
||||
Testing 1 ms delayed sleep callback...
|
||||
cDelayCallback=1001
|
||||
cDelayTotal=10669
|
||||
|
||||
|
||||
ESP8266 at 80MHz
|
||||
=================================
|
||||
Testing empty sleep callback...
|
||||
cEmptyCallback=1001
|
||||
cEmptyTotal=278101
|
||||
Testing 1 ms delayed sleep callback...
|
||||
cDelayCallback=1001
|
||||
cDelayTotal=10493
|
||||
|
||||
|
||||
ESP8266 at 160MHz
|
||||
=================================
|
||||
Testing empty sleep callback...
|
||||
cEmptyCallback=1001
|
||||
cEmptyTotal=546041
|
||||
Testing 1 ms delayed sleep callback...
|
||||
cDelayCallback=1001
|
||||
cDelayTotal=10746
|
||||
|
||||
|
||||
Maple Mini STM32 board at 70MHz -O3 code optimization
|
||||
==================================
|
||||
Testing empty sleep callback...
|
||||
cEmptyCallback=1001
|
||||
cEmptyTotal=2689973
|
||||
Testing 1 ms delayed sleep callback...
|
||||
cDelayCallback=1001
|
||||
cDelayTotal=10958
|
||||
|
||||
|
||||
esp32 at 240MHz
|
||||
==================================
|
||||
Testing empty sleep callback...
|
||||
cEmptyCallback=1001
|
||||
cEmptyTotal=492851
|
||||
Testing 1 ms delayed sleep callback...
|
||||
cDelayCallback=1001
|
||||
cDelayTotal=11002
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#define _TASK_SLEEP_ON_IDLE_RUN
|
||||
#include <TaskScheduler.h>
|
||||
|
||||
Scheduler ts;
|
||||
|
||||
// Callback methods prototypes
|
||||
void Count();
|
||||
bool tEmptyOn();
|
||||
void tEmptyOff();
|
||||
bool tDelayOn();
|
||||
void tDelayOff();
|
||||
|
||||
// Sleep methods prototypes
|
||||
void sEmpty(unsigned long aT);
|
||||
void sDelay(unsigned long aT);
|
||||
|
||||
// Tasks
|
||||
Task tCount ( 10, TASK_FOREVER, &Count, &ts, false );
|
||||
Task tEmpty ( 10000, TASK_ONCE, NULL, &ts, false, &tEmptyOn, &tEmptyOff );
|
||||
Task tDelay ( 10000, TASK_ONCE, NULL, &ts, false, &tDelayOn, &tDelayOff );
|
||||
|
||||
|
||||
volatile unsigned long cEmptyCallback, cEmptyTotal, cDelayCallback, cDelayTotal;
|
||||
volatile unsigned long *cCB, *cTL;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(5000);
|
||||
Serial.println("Start counting...");
|
||||
ts.setSleepMethod( &sEmpty );
|
||||
tEmpty.restartDelayed();
|
||||
}
|
||||
|
||||
|
||||
void sEmpty(unsigned long aT) {
|
||||
}
|
||||
|
||||
void sDelay(unsigned long aT) {
|
||||
delay(1);
|
||||
}
|
||||
|
||||
bool tEmptyOn() {
|
||||
Serial.println("Testing empty sleep callback...");
|
||||
cCB = &cEmptyCallback;
|
||||
cTL = &cEmptyTotal;
|
||||
|
||||
*cCB = 0;
|
||||
*cTL = 0;
|
||||
|
||||
tCount.restart();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tEmptyOff() {
|
||||
tCount.disable();
|
||||
|
||||
Serial.print("cEmptyCallback="); Serial.println(*cCB);
|
||||
Serial.print("cEmptyTotal="); Serial.println(*cTL);
|
||||
|
||||
ts.setSleepMethod( &sDelay );
|
||||
tDelay.restartDelayed();
|
||||
}
|
||||
|
||||
|
||||
bool tDelayOn() {
|
||||
Serial.println("Testing 1 ms delayed sleep callback...");
|
||||
cCB = &cDelayCallback;
|
||||
cTL = &cDelayTotal;
|
||||
|
||||
*cCB = 0;
|
||||
*cTL = 0;
|
||||
|
||||
tCount.restart();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tDelayOff() {
|
||||
tCount.disable();
|
||||
|
||||
Serial.print("cDelayCallback="); Serial.println(*cCB);
|
||||
Serial.print("cDelayTotal="); Serial.println(*cTL);
|
||||
}
|
||||
|
||||
void Count() {
|
||||
(*cCB)++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
ts.execute();
|
||||
(*cTL)++;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
/**
|
||||
This sketch collects scheduling overhead and CPU Idle Sleep information.
|
||||
A task is invoked every 10 milliseconds for 10 seconds.
|
||||
CPU statistics are collected
|
||||
|
||||
Compile and run once with _TASK_SLEEP_ON_IDLE_RUN enabled, then with _TASK_SLEEP_ON_IDLE_RUN disabled.
|
||||
Compare the results.
|
||||
*/
|
||||
|
||||
#define _TASK_ESP8266_DLY_THRESHOLD 50L
|
||||
#define _TASK_ESP32_DLY_THRESHOLD 40L
|
||||
|
||||
#define _TASK_SLEEP_ON_IDLE_RUN
|
||||
#define _TASK_TIMECRITICAL
|
||||
#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();
|
||||
unsigned long cpuTot = ts.getCpuLoadTotal();
|
||||
unsigned long cpuCyc = ts.getCpuLoadCycle();
|
||||
unsigned long cpuIdl = ts.getCpuLoadIdle();
|
||||
|
||||
Serial.print("Loop counts c1="); Serial.println(c1);
|
||||
Serial.print("Task counts c2="); Serial.println(c2);
|
||||
Serial.print("Total CPU time="); Serial.print(cpuTot); Serial.println(" micros");
|
||||
Serial.print("Scheduling Overhead CPU time="); Serial.print(cpuCyc); Serial.println(" micros");
|
||||
Serial.print("Idle Sleep CPU time="); Serial.print(cpuIdl); Serial.println(" micros");
|
||||
Serial.print("Productive work CPU time="); Serial.print(cpuTot - cpuIdl - cpuCyc); Serial.println(" micros");
|
||||
Serial.println();
|
||||
|
||||
float idle = (float)cpuIdl / (float)cpuTot * 100;
|
||||
Serial.print("CPU Idle Sleep "); Serial.print(idle); Serial.println(" % of time.");
|
||||
|
||||
float prod = (float)(cpuIdl + cpuCyc) / (float)cpuTot * 100;
|
||||
Serial.print("Productive work (not idle, not scheduling)"); Serial.print(100.00 - prod); Serial.println(" % of time.");
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
Serial.println("CPU Time Measurement");
|
||||
Serial.println("Start");
|
||||
|
||||
ts.startNow();
|
||||
t.delay();
|
||||
ts.cpuLoadReset();
|
||||
}
|
||||
|
||||
void Count() {
|
||||
c2++; // number of task callback invocations
|
||||
|
||||
// Try different delay intervals to see CPU statistics change
|
||||
// delay(1);
|
||||
// delay(5);
|
||||
// delay(10);
|
||||
// delay(20);
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
ts.execute();
|
||||
c1++; // number of loop() cycles
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
TaskScheduler Example #25
|
||||
|
||||
Create 10 random Tasks. Prints the entire chain.
|
||||
Then executes chain once printing the remaining chain from currently active task
|
||||
Deletes all tasks afterwards
|
||||
*/
|
||||
|
||||
// #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
|
||||
// #define _TASK_DEFINE_MILLIS // Force forward declaration of millis() and micros() "C" style
|
||||
#define _TASK_EXPOSE_CHAIN // Methods to access tasks in the task chain
|
||||
|
||||
#include <TaskScheduler.h>
|
||||
#include <QueueArray.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 taskCallback();
|
||||
void cleanUp();
|
||||
|
||||
Task tManager(6000, TASK_ONCE, &cleanUp, &ts, false);
|
||||
/*
|
||||
Scheduling defines:
|
||||
TASK_MILLISECOND
|
||||
TASK_SECOND
|
||||
TASK_MINUTE
|
||||
TASK_HOUR
|
||||
TASK_IMMEDIATE
|
||||
TASK_FOREVER
|
||||
TASK_ONCE
|
||||
TASK_NOTIMEOUT
|
||||
*/
|
||||
|
||||
int noOfTasks = 10;
|
||||
QueueArray <Task*> toDelete;
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
#if defined(_DEBUG_) || defined(_TEST_)
|
||||
Serial.begin(115200);
|
||||
delay(2000);
|
||||
_PL("Scheduler Example: Expose Scheduler Task Chain"); _PL();
|
||||
#endif
|
||||
|
||||
_PL("Generating a random chain of tasks");
|
||||
for (int i = 0; i < noOfTasks; i++) {
|
||||
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, &taskCallback, &ts, false);
|
||||
_PP(F("Generated a new task:\t")); _PP(t->getId()); _PP(F("\tInt, Iter = \t"));
|
||||
_PP(p); Serial.print(", "); _PL(j);
|
||||
if ( random(1, 100) > 50 ) {
|
||||
t->enable();
|
||||
}
|
||||
else {
|
||||
t->enableDelayed();
|
||||
}
|
||||
toDelete.push(t);
|
||||
}
|
||||
_PL();
|
||||
_PL("Printing the entire chain");
|
||||
Task* f = ts.getFirstTask();
|
||||
Task* l = ts.getLastTask();
|
||||
while (f) {
|
||||
_PP("Task #"); _PL(f->getId());
|
||||
f = f->getNextTask();
|
||||
}
|
||||
_PL();
|
||||
tManager.enableDelayed();
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
ts.execute();
|
||||
}
|
||||
|
||||
|
||||
void taskCallback() {
|
||||
_PP(millis());
|
||||
_PP(": taskCallback() of task #");
|
||||
Task* t = ts.getCurrentTask();
|
||||
t->disable();
|
||||
_PL(t->getId());
|
||||
Task* l = ts.getLastTask();
|
||||
while (t) {
|
||||
_PP("#"); _PP(t->getId());
|
||||
if (t->getNextTask() != NULL) _PP("->");
|
||||
t = t->getNextTask();
|
||||
}
|
||||
_PL(); _PL();
|
||||
}
|
||||
|
||||
void cleanUp() {
|
||||
_PL("Deleting tasks:");
|
||||
do {
|
||||
Task* t = toDelete.pop();
|
||||
_PP("Deleting task #"); _PL(t->getId());
|
||||
delete t;
|
||||
} while (!toDelete.isEmpty());
|
||||
|
||||
for (;;) ;
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
Example of scheduling options:
|
||||
|
||||
t1 - is a default option with priority given to schedule, i.e., scheduler tries
|
||||
maintain original schedule and performs task "catch up" to ensure the number
|
||||
of iterations that were supposed to happen do happen.
|
||||
|
||||
t2 - is an option with priority given to schedule, but without "catch up"
|
||||
the scheduler will try to maintain original schedule, but next task invocation
|
||||
is always scheduled to happen in the future
|
||||
|
||||
t3 - is a option with priority given to interval. Task are scheduled always in the
|
||||
future from the point of their current invocation start using task's interval.
|
||||
|
||||
|
||||
*/
|
||||
// ==== DEFINES ===================================================================================
|
||||
|
||||
// ==== Debug and Test options ==================
|
||||
#define _DEBUG_
|
||||
//#define _TEST_
|
||||
|
||||
//===== Debugging macros ========================
|
||||
#ifdef _DEBUG_
|
||||
#define SerialD Serial
|
||||
#define _PM(a) SerialD.print(millis()); SerialD.print(": "); SerialD.println(a)
|
||||
#define _PP(a) SerialD.print(a)
|
||||
#define _PL(a) SerialD.println(a)
|
||||
#define _PX(a) SerialD.println(a, HEX)
|
||||
#else
|
||||
#define _PM(a)
|
||||
#define _PP(a)
|
||||
#define _PL(a)
|
||||
#define _PX(a)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
// ==== INCLUDES ==================================================================================
|
||||
|
||||
// ==== Uncomment desired compile options =================================
|
||||
// #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
|
||||
// #define _TASK_DEFINE_MILLIS // Force forward declaration of millis() and micros() "C" style
|
||||
// #define _TASK_EXPOSE_CHAIN // Methods to access tasks in the task chain
|
||||
#define _TASK_SCHEDULING_OPTIONS // Support for multiple scheduling options
|
||||
#include <TaskScheduler.h>
|
||||
|
||||
|
||||
|
||||
// ==== GLOBALS ===================================================================================
|
||||
// ==== Scheduler ==============================
|
||||
Scheduler ts;
|
||||
|
||||
void t1CB();
|
||||
void t2CB();
|
||||
void t3CB();
|
||||
|
||||
// ==== Scheduling defines (cheat sheet) =====================
|
||||
/*
|
||||
TASK_MILLISECOND
|
||||
TASK_SECOND
|
||||
TASK_MINUTE
|
||||
TASK_HOUR
|
||||
TASK_IMMEDIATE
|
||||
TASK_FOREVER
|
||||
TASK_ONCE
|
||||
TASK_NOTIMEOUT
|
||||
|
||||
TASK_SCHEDULE - schedule is a priority, with "catch up" (default)
|
||||
TASK_SCHEDULE_NC - schedule is a priority, without "catch up"
|
||||
TASK_INTERVAL - interval is a priority, without "catch up"
|
||||
*/
|
||||
|
||||
// ==== Task definitions ========================
|
||||
Task t1_schedule (100 * TASK_MILLISECOND, 10, &t1CB, &ts);
|
||||
Task t2_schedule_nc (100 * TASK_MILLISECOND, 10, &t2CB, &ts);
|
||||
Task t3_interval (100 * TASK_MILLISECOND, 10, &t3CB, &ts);
|
||||
|
||||
|
||||
|
||||
// ==== CODE ======================================================================================
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Standard Arduino SETUP method - initialize sketch
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
#if defined(_DEBUG_) || defined(_TEST_)
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
_PL("Scheduling Options: setup()");
|
||||
#endif
|
||||
|
||||
t2_schedule_nc.setSchedulingOption(TASK_SCHEDULE_NC);
|
||||
t3_interval.setSchedulingOption(TASK_INTERVAL);
|
||||
|
||||
|
||||
_PM("t1 start time");
|
||||
t1_schedule.enable();
|
||||
delay(10);
|
||||
|
||||
_PM("t2 start time");
|
||||
t2_schedule_nc.enable();
|
||||
delay(10);
|
||||
|
||||
_PM("t3 start time");
|
||||
t3_interval.enable();
|
||||
|
||||
delay(333);
|
||||
_PM("333 ms delay ended");
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Standard Arduino LOOP method - using with TaskScheduler there
|
||||
should be nothing here but ts.execute()
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop() {
|
||||
ts.execute();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Callback method of task1 - explain
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void t1CB() {
|
||||
_PM("t1CB()");
|
||||
// task code
|
||||
delay(10);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Callback method of task2 - explain
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void t2CB() {
|
||||
_PM("t2CB()");
|
||||
// task code
|
||||
delay(10);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Callback method of task3 - explain
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void t3CB() {
|
||||
_PM("t3CB()");
|
||||
// task code
|
||||
delay(10);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef _TS27_LED_H
|
||||
#define _TS27_LED_H
|
||||
|
||||
// LED_BUILTIN 13
|
||||
#if defined( ARDUINO_ARCH_ESP32 )
|
||||
#define LED_BUILTIN 23 // esp32 dev2 kit does not have LED
|
||||
#endif
|
||||
|
||||
void LEDOff();
|
||||
void LEDOn();
|
||||
|
||||
#endif // _TS27_LED_H
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef _TS27_MAIN_H
|
||||
#define _TS27_MAIN_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef _DEBUG_
|
||||
#define _PP(a) Serial.print(a);
|
||||
#define _PL(a) Serial.println(a);
|
||||
#else
|
||||
#define _PP(a)
|
||||
#define _PL(a)
|
||||
#endif
|
||||
|
||||
#define PERIOD1 500
|
||||
#define DURATION 10000
|
||||
|
||||
#define PERIOD2 400
|
||||
|
||||
#define PERIOD3 300
|
||||
|
||||
#define PERIOD4 200
|
||||
|
||||
#define PERIOD5 600
|
||||
|
||||
#define PERIOD6 300
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
@@ -0,0 +1,38 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp32dev]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
|
||||
[env]
|
||||
lib_deps =
|
||||
arkhipenko/TaskScheduler @ ^3.4.0
|
||||
|
||||
build_flags =
|
||||
; -D _TASK_TIMECRITICAL
|
||||
-D _TASK_SLEEP_ON_IDLE_RUN
|
||||
-D _TASK_STATUS_REQUEST
|
||||
; -D _TASK_WDT_IDS
|
||||
; -D _TASK_LTS_POINTER
|
||||
; -D _TASK_PRIORITY
|
||||
; -D _TASK_MICRO_RES
|
||||
; -D _TASK_STD_FUNCTION
|
||||
; -D _TASK_DEBUG
|
||||
; -D _TASK_INLINE
|
||||
; -D _TASK_TIMEOUT
|
||||
; -D _TASK_OO_CALLBACKS
|
||||
; -D _TASK_EXPOSE_CHAIN
|
||||
; -D _TASK_SCHEDULING_OPTIONS
|
||||
; -D _TASK_DEFINE_MILLIS
|
||||
; -D _TASK_EXTERNAL_TIME
|
||||
-D _DEBUG_
|
||||
; -D _TEST_
|
||||
@@ -0,0 +1 @@
|
||||
#include <TaskScheduler.h>
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <Arduino.h>
|
||||
#include "led.h"
|
||||
#include "main.h"
|
||||
|
||||
void LEDOn() {
|
||||
digitalWrite( LED_BUILTIN, HIGH );
|
||||
}
|
||||
|
||||
void LEDOff() {
|
||||
digitalWrite( LED_BUILTIN, LOW );
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
Every example set must have a LED blink example
|
||||
For this one the idea is to have as many ways to blink the LED
|
||||
as I can think of. So, here we go.
|
||||
|
||||
Tested on:
|
||||
- Arduino Nano
|
||||
- ESP8266
|
||||
- ESP32
|
||||
- STM32 Maple Mini
|
||||
*/
|
||||
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "led.h"
|
||||
|
||||
// Scheduler
|
||||
Scheduler ts;
|
||||
|
||||
/*
|
||||
Approach 1: LED is driven by the boolean variable; false = OFF, true = ON
|
||||
*/
|
||||
void blink1CB();
|
||||
Task tBlink1 ( PERIOD1 * TASK_MILLISECOND, DURATION / PERIOD1, &blink1CB, &ts, true );
|
||||
|
||||
/*
|
||||
Approach 2: two callback methods: one turns ON, another turns OFF
|
||||
*/
|
||||
void blink2CB_ON();
|
||||
void blink2CB_OFF();
|
||||
Task tBlink2 ( PERIOD2 * TASK_MILLISECOND, DURATION / PERIOD2, &blink2CB_ON, &ts, false );
|
||||
|
||||
/*
|
||||
Approach 3: Use RunCounter
|
||||
*/
|
||||
void blink3CB();
|
||||
Task tBlink3 (PERIOD3 * TASK_MILLISECOND, DURATION / PERIOD3, &blink3CB, &ts, false);
|
||||
|
||||
/*
|
||||
Approach 4: Use status request objects to pass control from one task to the other
|
||||
*/
|
||||
bool blink41OE();
|
||||
void blink41();
|
||||
void blink42();
|
||||
void blink42OD();
|
||||
Task tBlink4On ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink41, &ts, false, &blink41OE );
|
||||
Task tBlink4Off ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink42, &ts, false, NULL, &blink42OD );
|
||||
|
||||
|
||||
/*
|
||||
Approach 5: Two interleaving tasks
|
||||
*/
|
||||
bool blink51OE();
|
||||
void blink51();
|
||||
void blink52();
|
||||
void blink52OD();
|
||||
Task tBlink5On ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink51, &ts, false, &blink51OE );
|
||||
Task tBlink5Off ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink52, &ts, false, NULL, &blink52OD );
|
||||
|
||||
|
||||
/*
|
||||
Approach 6: RunCounter-based with random intervals
|
||||
*/
|
||||
void blink6CB();
|
||||
bool blink6OE();
|
||||
void blink6OD();
|
||||
Task tBlink6 ( PERIOD6 * TASK_MILLISECOND, DURATION / PERIOD6, &blink6CB, &ts, false, &blink6OE, &blink6OD );
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
#if defined(_DEBUG_) || defined(_TEST_)
|
||||
Serial.begin(115200);
|
||||
delay(TASK_SECOND);
|
||||
_PL("TaskScheduler Blink example");
|
||||
_PL("Blinking for 10 seconds using various techniques\n");
|
||||
delay(2 * TASK_SECOND);
|
||||
#endif
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
ts.execute();
|
||||
}
|
||||
|
||||
// === 1 =======================================
|
||||
bool LED_state = false;
|
||||
void blink1CB() {
|
||||
if ( tBlink1.isFirstIteration() ) {
|
||||
_PP(millis());
|
||||
_PL(": Blink1 - simple flag driven");
|
||||
LED_state = false;
|
||||
}
|
||||
|
||||
if ( LED_state ) {
|
||||
LEDOff();
|
||||
LED_state = false;
|
||||
}
|
||||
else {
|
||||
LEDOn();
|
||||
LED_state = true;
|
||||
}
|
||||
|
||||
if ( tBlink1.isLastIteration() ) {
|
||||
tBlink2.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === 2 ======================================
|
||||
void blink2CB_ON() {
|
||||
if ( tBlink2.isFirstIteration() ) {
|
||||
_PP(millis());
|
||||
_PL(": Blink2 - 2 callback methods");
|
||||
}
|
||||
|
||||
LEDOn();
|
||||
tBlink2.setCallback( &blink2CB_OFF );
|
||||
|
||||
if ( tBlink2.isLastIteration() ) {
|
||||
tBlink3.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void blink2CB_OFF() {
|
||||
|
||||
LEDOff();
|
||||
tBlink2.setCallback( &blink2CB_ON );
|
||||
|
||||
if ( tBlink2.isLastIteration() ) {
|
||||
tBlink3.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === 3 =====================================
|
||||
void blink3CB() {
|
||||
if ( tBlink3.isFirstIteration() ) {
|
||||
_PP(millis());
|
||||
_PL(": Blink3 - Run Counter driven");
|
||||
}
|
||||
|
||||
if ( tBlink3.getRunCounter() & 1 ) {
|
||||
LEDOn();
|
||||
}
|
||||
else {
|
||||
LEDOff();
|
||||
}
|
||||
|
||||
if ( tBlink3.isLastIteration() ) {
|
||||
tBlink4On.setOnEnable( &blink41OE );
|
||||
tBlink4On.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === 4 =============================================
|
||||
int counter = 0;
|
||||
bool blink41OE() {
|
||||
_PP(millis());
|
||||
_PL(": Blink4 - Internal status request based");
|
||||
counter = 0;
|
||||
tBlink4On.setOnEnable( NULL );
|
||||
return true;
|
||||
}
|
||||
|
||||
void blink41() {
|
||||
// _PP(millis());
|
||||
// _PL(": blink41");
|
||||
LEDOn();
|
||||
StatusRequest* r = tBlink4On.getInternalStatusRequest();
|
||||
tBlink4Off.waitForDelayed( r );
|
||||
counter++;
|
||||
}
|
||||
|
||||
void blink42() {
|
||||
// _PP(millis());
|
||||
// _PL(": blink42");
|
||||
LEDOff();
|
||||
StatusRequest* r = tBlink4Off.getInternalStatusRequest();
|
||||
tBlink4On.waitForDelayed( r );
|
||||
counter++;
|
||||
}
|
||||
|
||||
|
||||
void blink42OD() {
|
||||
if ( counter >= DURATION / PERIOD4 ) {
|
||||
tBlink4On.disable();
|
||||
tBlink4Off.disable();
|
||||
|
||||
tBlink5On.setOnEnable( &blink51OE );
|
||||
tBlink5On.restartDelayed( 2 * TASK_SECOND );
|
||||
tBlink5Off.restartDelayed( 2 * TASK_SECOND + PERIOD5 / 2 );
|
||||
LEDOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === 5 ==========================================
|
||||
bool blink51OE() {
|
||||
_PP(millis());
|
||||
_PL(": Blink5 - Two interleaving tasks");
|
||||
tBlink5On.setOnEnable( NULL );
|
||||
return true;
|
||||
}
|
||||
void blink51() {
|
||||
// _PP(millis());
|
||||
// _PL(": blink51");
|
||||
LEDOn();
|
||||
}
|
||||
void blink52() {
|
||||
// _PP(millis());
|
||||
// _PL(": blink52");
|
||||
LEDOff();
|
||||
}
|
||||
void blink52OD() {
|
||||
tBlink6.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
|
||||
|
||||
// === 6 ============================================
|
||||
long interval6 = 0;
|
||||
bool blink6OE() {
|
||||
_PP(millis());
|
||||
_PP(": Blink6 - RunCounter + Random ON interval = ");
|
||||
interval6 = random( 100, 901 );
|
||||
tBlink6.setInterval( interval6 );
|
||||
_PL( interval6 );
|
||||
tBlink6.delay( 2 * TASK_SECOND );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void blink6CB() {
|
||||
if ( tBlink6.getRunCounter() & 1 ) {
|
||||
LEDOn();
|
||||
tBlink6.setInterval( interval6 );
|
||||
}
|
||||
else {
|
||||
LEDOff();
|
||||
tBlink6.setInterval( TASK_SECOND - interval6 );
|
||||
}
|
||||
}
|
||||
|
||||
void blink6OD() {
|
||||
tBlink1.restartDelayed( 2 * TASK_SECOND );
|
||||
LEDOff();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Your code description here
|
||||
(c) you, 20XX
|
||||
All rights reserved.
|
||||
|
||||
Functionality:
|
||||
|
||||
Version log:
|
||||
|
||||
20XX-MM-DD:
|
||||
v1.0.0 - Initial release
|
||||
|
||||
*/
|
||||
// ==== DEFINES ===================================================================================
|
||||
|
||||
// ==== Debug and Test options ==================
|
||||
#define _DEBUG_
|
||||
//#define _TEST_
|
||||
|
||||
//===== Debugging macros ========================
|
||||
#ifdef _DEBUG_
|
||||
#define SerialD Serial
|
||||
#define _PM(a) SerialD.print(millis()); SerialD.print(": "); SerialD.println(a)
|
||||
#define _PP(a) SerialD.print(a)
|
||||
#define _PL(a) SerialD.println(a)
|
||||
#define _PX(a) SerialD.println(a, HEX)
|
||||
#else
|
||||
#define _PM(a)
|
||||
#define _PP(a)
|
||||
#define _PL(a)
|
||||
#define _PX(a)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
// ==== INCLUDES ==================================================================================
|
||||
|
||||
// ==== Uncomment desired compile options =================================
|
||||
// #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_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_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
|
||||
// #define _TASK_DEFINE_MILLIS // Force forward declaration of millis() and micros() "C" style
|
||||
// #define _TASK_EXPOSE_CHAIN // Methods to access tasks in the task chain
|
||||
// #define _TASK_SCHEDULING_OPTIONS // Support for multiple scheduling options
|
||||
|
||||
#include <TaskScheduler.h>
|
||||
|
||||
|
||||
|
||||
// ==== GLOBALS ===================================================================================
|
||||
// ==== Scheduler ==============================
|
||||
Scheduler ts;
|
||||
|
||||
void task1Callback();
|
||||
void task2Callback();
|
||||
|
||||
// ==== Scheduling defines (cheat sheet) =====================
|
||||
/*
|
||||
TASK_MILLISECOND
|
||||
TASK_SECOND
|
||||
TASK_MINUTE
|
||||
TASK_HOUR
|
||||
TASK_IMMEDIATE
|
||||
TASK_FOREVER
|
||||
TASK_ONCE
|
||||
TASK_NOTIMEOUT
|
||||
|
||||
TASK_SCHEDULE - schedule is a priority, with "catch up" (default)
|
||||
TASK_SCHEDULE_NC - schedule is a priority, without "catch up"
|
||||
TASK_INTERVAL - interval is a priority, without "catch up"
|
||||
*/
|
||||
|
||||
// ==== Task definitions ========================
|
||||
Task t1 (100 * TASK_MILLISECOND, TASK_FOREVER, &task1Callback, &ts, true);
|
||||
Task t2 (TASK_IMMEDIATE, 100, &task2Callback, &ts, true);
|
||||
|
||||
|
||||
|
||||
// ==== CODE ======================================================================================
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Standard Arduino SETUP method - initialize sketch
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Standard Arduino LOOP method - using with TaskScheduler there
|
||||
should be nothing here but ts.execute()
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop() {
|
||||
ts.execute();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Callback method of task1 - explain
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void task1Callback() {
|
||||
_PM("task1Callback()");
|
||||
// task code
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Callback method of task2 - explain
|
||||
@param none
|
||||
@returns none
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void task2Callback() {
|
||||
_PM("task2Callback()");
|
||||
// task code
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user