Skip to content

Commit e7703d4

Browse files
committed
v3.7.0 - optional self-destruct of tasks on disable
1 parent 25b1db7 commit e7703d4

File tree

14 files changed

+450
-77
lines changed

14 files changed

+450
-77
lines changed

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Task Scheduler
22
### Cooperative multitasking for Arduino, ESPx, STM32 and other microcontrollers
3-
#### Version 3.6.2: 2022-10-04 [Latest updates](https://github.com/arkhipenko/TaskScheduler/wiki/Latest-Updates)
3+
#### Version 3.7.0: 2022-10-10 [Latest updates](https://github.com/arkhipenko/TaskScheduler/wiki/Latest-Updates)
44

55
[![arduino-library-badge](https://www.ardu-badge.com/badge/TaskScheduler.svg?)](https://www.ardu-badge.com/TaskScheduler)[![xscode](https://img.shields.io/badge/Available%20on-xs%3Acode-blue?style=?style=plastic&logo=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF////////VXz1bAAAAAJ0Uk5T/wDltzBKAAAAlUlEQVR42uzXSwqAMAwE0Mn9L+3Ggtgkk35QwcnSJo9S+yGwM9DCooCbgn4YrJ4CIPUcQF7/XSBbx2TEz4sAZ2q1RAECBAiYBlCtvwN+KiYAlG7UDGj59MViT9hOwEqAhYCtAsUZvL6I6W8c2wcbd+LIWSCHSTeSAAECngN4xxIDSK9f4B9t377Wd7H5Nt7/Xz8eAgwAvesLRjYYPuUAAAAASUVORK5CYII=)](https://xscode.com/arkhipenko/TaskScheduler)
66

@@ -34,7 +34,8 @@ _“Everybody who learns concurrency and thinks they understand it, ends up find
3434
13. CPU load / idle statistics for time critical applications
3535
14. Scheduling options with priority for original schedule (with and without catchup) and interval
3636
15. Ability to pause/resume and enable/disable scheduling
37-
15. Thread-safe scheduling while running under preemptive scheduler (i. e., FreeRTOS)
37+
16. Thread-safe scheduling while running under preemptive scheduler (i. e., FreeRTOS)
38+
17. Optional self-destruction of dynamically created tasks upon disable
3839

3940
Scheduling overhead: between `15` and `18` microseconds per scheduling pass (Arduino UNO rev 3 @ `16MHz` clock, single scheduler w/o prioritization)
4041

@@ -43,7 +44,7 @@ Scheduling overhead: between `15` and `18` microseconds per scheduling pass (Ard
4344
* Arduino Nano
4445
* Arduino Micro
4546
* ATtiny85
46-
* ESP8266 (Node MCU v2.0)
47+
* ESP8266
4748
* ESP32
4849
* Teensy (tested on Teensy 3.5)
4950
* nRF52 (tested on nRF52832)

examples/Scheduler_example00_Blink/Scheduler_example00_Blink.ino

+22-13
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,28 @@
1010
- STM32 Maple Mini
1111
*/
1212

13-
14-
// #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
15-
#define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between tasks if no callback methods were invoked during the pass
16-
#define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
17-
// #define _TASK_WDT_IDS // Compile with support for wdt control points and task ids
18-
// #define _TASK_LTS_POINTER // Compile with support for local task storage pointer
19-
// #define _TASK_PRIORITY // Support for layered scheduling priority
20-
// #define _TASK_MICRO_RES // Support for microsecond resolution
21-
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 and ESP32 ONLY)
22-
// #define _TASK_DEBUG // Make all methods and variables public for debug purposes
23-
// #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
24-
// #define _TASK_TIMEOUT // Support for overall task timeout
25-
// #define _TASK_OO_CALLBACKS // Support for dynamic callback method binding
13+
// ----------------------------------------
14+
// The following "defines" control library functionality at compile time,
15+
// and should be used in the main sketch depending on the functionality required
16+
//
17+
// #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
18+
#define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between runs if no callback methods were invoked during the pass
19+
#define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
20+
// #define _TASK_WDT_IDS // Compile with support for wdt control points and task ids
21+
// #define _TASK_LTS_POINTER // Compile with support for local task storage pointer
22+
// #define _TASK_PRIORITY // Support for layered scheduling priority
23+
// #define _TASK_MICRO_RES // Support for microsecond resolution
24+
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 ONLY)
25+
// #define _TASK_DEBUG // Make all methods and variables public for debug purposes
26+
// #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
27+
// #define _TASK_TIMEOUT // Support for overall task timeout
28+
// #define _TASK_OO_CALLBACKS // Support for callbacks via inheritance
29+
// #define _TASK_EXPOSE_CHAIN // Methods to access tasks in the task chain
30+
// #define _TASK_SCHEDULING_OPTIONS // Support for multiple scheduling options
31+
// #define _TASK_DEFINE_MILLIS // Force forward declaration of millis() and micros() "C" style
32+
// #define _TASK_EXTERNAL_TIME // Custom millis() and micros() methods
33+
// #define _TASK_THREAD_SAFE // Enable additional checking for thread safety
34+
// #define _TASK_SELF_DESTRUCT // Enable tasks to "self-destruct" after disable
2635
#include <TaskScheduler.h>
2736

2837
// Debug and Test options

examples/Scheduler_example00_Blink_Adafruit/Scheduler_example00_Blink_Adafruit.ino renamed to examples/Scheduler_example00_Blink_Namespace/Scheduler_example00_Blink_Namespace.ino

+34-23
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,29 @@
88
*/
99

1010

11-
// #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
12-
#define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between tasks if no callback methods were invoked during the pass
13-
#define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
14-
// #define _TASK_WDT_IDS // Compile with support for wdt control points and task ids
15-
// #define _TASK_LTS_POINTER // Compile with support for local task storage pointer
16-
// #define _TASK_PRIORITY // Support for layered scheduling priority
17-
// #define _TASK_MICRO_RES // Support for microsecond resolution
18-
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 and ESP32 ONLY)
19-
// #define _TASK_DEBUG // Make all methods and variables public for debug purposes
20-
// #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
21-
// #define _TASK_TIMEOUT // Support for overall task timeout
22-
// #define _TASK_OO_CALLBACKS // Support for dynamic callback method binding
11+
// ----------------------------------------
12+
// The following "defines" control library functionality at compile time,
13+
// and should be used in the main sketch depending on the functionality required
14+
//
15+
// #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
16+
#define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between runs if no callback methods were invoked during the pass
17+
#define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
18+
// #define _TASK_WDT_IDS // Compile with support for wdt control points and task ids
19+
// #define _TASK_LTS_POINTER // Compile with support for local task storage pointer
20+
// #define _TASK_PRIORITY // Support for layered scheduling priority
21+
// #define _TASK_MICRO_RES // Support for microsecond resolution
22+
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 ONLY)
23+
// #define _TASK_DEBUG // Make all methods and variables public for debug purposes
24+
// #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
25+
// #define _TASK_TIMEOUT // Support for overall task timeout
26+
// #define _TASK_OO_CALLBACKS // Support for callbacks via inheritance
27+
// #define _TASK_EXPOSE_CHAIN // Methods to access tasks in the task chain
28+
// #define _TASK_SCHEDULING_OPTIONS // Support for multiple scheduling options
29+
// #define _TASK_DEFINE_MILLIS // Force forward declaration of millis() and micros() "C" style
30+
// #define _TASK_EXTERNAL_TIME // Custom millis() and micros() methods
31+
// #define _TASK_THREAD_SAFE // Enable additional checking for thread safety
32+
// #define _TASK_SELF_DESTRUCT // Enable tasks to "self-destruct" after disable
33+
2334
#include <TScheduler.hpp>
2435

2536
// Debug and Test options
@@ -40,30 +51,30 @@
4051
#endif
4152

4253
// Scheduler
43-
TaskScheduler ts;
54+
TsScheduler ts;
4455

4556
/*
4657
Approach 1: LED is driven by the boolean variable; false = OFF, true = ON
4758
*/
4859
#define PERIOD1 500
4960
#define DURATION 10000
5061
void blink1CB();
51-
Task tBlink1 ( PERIOD1 * TASK_MILLISECOND, DURATION / PERIOD1, &blink1CB, &ts, true );
62+
TsTask tBlink1 ( PERIOD1 * TASK_MILLISECOND, DURATION / PERIOD1, &blink1CB, &ts, true );
5263

5364
/*
5465
Approac 2: two callback methods: one turns ON, another turns OFF
5566
*/
5667
#define PERIOD2 400
5768
void blink2CB_ON();
5869
void blink2CB_OFF();
59-
Task tBlink2 ( PERIOD2 * TASK_MILLISECOND, DURATION / PERIOD2, &blink2CB_ON, &ts, false );
70+
TsTask tBlink2 ( PERIOD2 * TASK_MILLISECOND, DURATION / PERIOD2, &blink2CB_ON, &ts, false );
6071

6172
/*
6273
Approach 3: Use RunCounter
6374
*/
6475
#define PERIOD3 300
6576
void blink3CB();
66-
Task tBlink3 (PERIOD3 * TASK_MILLISECOND, DURATION / PERIOD3, &blink3CB, &ts, false);
77+
TsTask tBlink3 (PERIOD3 * TASK_MILLISECOND, DURATION / PERIOD3, &blink3CB, &ts, false);
6778

6879
/*
6980
Approach 4: Use status request objects to pass control from one task to the other
@@ -73,8 +84,8 @@ bool blink41OE();
7384
void blink41();
7485
void blink42();
7586
void blink42OD();
76-
Task tBlink4On ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink41, &ts, false, &blink41OE );
77-
Task tBlink4Off ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink42, &ts, false, NULL, &blink42OD );
87+
TsTask tBlink4On ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink41, &ts, false, &blink41OE );
88+
TsTask tBlink4Off ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink42, &ts, false, NULL, &blink42OD );
7889

7990

8091
/*
@@ -85,8 +96,8 @@ bool blink51OE();
8596
void blink51();
8697
void blink52();
8798
void blink52OD();
88-
Task tBlink5On ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink51, &ts, false, &blink51OE );
89-
Task tBlink5Off ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink52, &ts, false, NULL, &blink52OD );
99+
TsTask tBlink5On ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink51, &ts, false, &blink51OE );
100+
TsTask tBlink5Off ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink52, &ts, false, NULL, &blink52OD );
90101

91102

92103
/*
@@ -96,7 +107,7 @@ Task tBlink5Off ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink52, &ts, fal
96107
void blink6CB();
97108
bool blink6OE();
98109
void blink6OD();
99-
Task tBlink6 ( PERIOD6 * TASK_MILLISECOND, DURATION / PERIOD6, &blink6CB, &ts, false, &blink6OE, &blink6OD );
110+
TsTask tBlink6 ( PERIOD6 * TASK_MILLISECOND, DURATION / PERIOD6, &blink6CB, &ts, false, &blink6OE, &blink6OD );
100111

101112
void setup() {
102113
// put your setup code here, to run once:
@@ -212,7 +223,7 @@ void blink41() {
212223
// _PP(millis());
213224
// _PL(": blink41");
214225
LEDOn();
215-
StatusRequest* r = tBlink4On.getInternalStatusRequest();
226+
TsStatusRequest* r = tBlink4On.getInternalStatusRequest();
216227
tBlink4Off.waitForDelayed( r );
217228
counter++;
218229
}
@@ -221,7 +232,7 @@ void blink42() {
221232
// _PP(millis());
222233
// _PL(": blink42");
223234
LEDOff();
224-
StatusRequest* r = tBlink4Off.getInternalStatusRequest();
235+
TsStatusRequest* r = tBlink4Off.getInternalStatusRequest();
225236
tBlink4On.waitForDelayed( r );
226237
counter++;
227238
}

examples/Scheduler_example19_Dynamic_Tasks/Scheduler_example19_Dynamic_Tasks.ino

+6-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <TaskScheduler.h>
1818
#include <QueueArray.h>
1919

20+
int freeMemory();
21+
2022
#if defined (ARDUINO_ARCH_AVR)
2123
#include <MemoryFree.h>
2224
#elif defined(__arm__)
@@ -25,8 +27,11 @@ static int freeMemory() {
2527
char top = 't';
2628
return &top - reinterpret_cast<char*>(sbrk(0));
2729
}
30+
#elif defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_ESP32)
31+
int freeMemory() { return ESP.getFreeHeap();}
2832
#else
29-
int freeMemory(); // supply your own
33+
// Supply your own freeMemory method
34+
int freeMemory() { return 0;}
3035
#endif
3136

3237
Scheduler ts;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
TaskScheduler Test sketch - test of Task destructor
3+
Test case:
4+
Main task runs every 100 milliseconds 100 times and in 50% cases generates a task object
5+
which runs 1 to 10 times with 100 ms to 5 s interval, and then destroyed.
6+
Self-destruct feature takes care of the task deletion after tasks complete
7+
8+
This sketch uses the following libraries:
9+
- FreeMemory library: https://github.com/McNeight/MemoryFree
10+
- QueueArray library: https://playground.arduino.cc/Code/QueueArray/
11+
*/
12+
13+
#define _TASK_WDT_IDS // To enable task unique IDs
14+
#define _TASK_SLEEP_ON_IDLE_RUN // Compile with support for entering IDLE SLEEP state for 1 ms if not tasks are scheduled to run
15+
#define _TASK_LTS_POINTER // Compile with support for Local Task Storage pointer
16+
#define _TASK_SELF_DESTRUCT // Enable tasks to "self-destruct" after disable
17+
#include <TaskScheduler.h>
18+
19+
int freeMemory();
20+
21+
#if defined (ARDUINO_ARCH_AVR)
22+
#include <MemoryFree.h>
23+
#elif defined(__arm__)
24+
extern "C" char* sbrk(int incr);
25+
static int freeMemory() {
26+
char top = 't';
27+
return &top - reinterpret_cast<char*>(sbrk(0));
28+
}
29+
#elif defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_ESP32)
30+
int freeMemory() { return ESP.getFreeHeap();}
31+
#else
32+
// Supply your own freeMemory method
33+
int freeMemory() { return 0;}
34+
#endif
35+
36+
Scheduler ts;
37+
38+
// Callback methods prototypes
39+
void MainLoop();
40+
void GC();
41+
42+
// Statis task
43+
Task tMain(100 * TASK_MILLISECOND, 100, &MainLoop, &ts, true);
44+
45+
void Iteration();
46+
bool OnEnable();
47+
void OnDisable();
48+
49+
int noOfTasks = 0;
50+
51+
void MainLoop() {
52+
Serial.print(millis()); Serial.print("\t");
53+
Serial.print("MainLoop run: ");
54+
int i = tMain.getRunCounter();
55+
Serial.print(i); Serial.print(F(".\t"));
56+
57+
if ( random(0, 101) > 50 ) { // generate a new task only in 50% of cases
58+
// Generating another task
59+
long p = random(100, 5001); // from 100 ms to 5 seconds
60+
long j = random(1, 11); // from 1 to 10 iterations)
61+
Task *t = new Task(p, j, Iteration, &ts, false, OnEnable, OnDisable, true); // enable self-destruct
62+
63+
Serial.print(F("Generated a new task:\t")); Serial.print(t->getId()); Serial.print(F("\tInt, Iter = \t"));
64+
Serial.print(p); Serial.print(", "); Serial.print(j);
65+
Serial.print(F("\tFree mem=")); Serial.print(freeMemory());
66+
Serial.print(F("\tNo of tasks=")); Serial.println(++noOfTasks);
67+
t->enable();
68+
}
69+
else {
70+
Serial.println(F("Skipped generating a task"));
71+
}
72+
}
73+
74+
75+
void Iteration() {
76+
Task &t = ts.currentTask();
77+
78+
Serial.print(millis()); Serial.print("\t");
79+
Serial.print("Task N"); Serial.print(t.getId()); Serial.print(F("\tcurrent iteration: "));
80+
int i = t.getRunCounter();
81+
Serial.println(i);
82+
}
83+
84+
bool OnEnable() {
85+
// to-do: think of something to put in here.
86+
return true;
87+
}
88+
89+
void OnDisable() {
90+
Task *t = &ts.currentTask();
91+
unsigned int tid = t->getId();
92+
93+
Serial.print(millis()); Serial.print("\t");
94+
Serial.print("Task N"); Serial.print(tid); Serial.println(F("\tfinished"));
95+
Serial.print(F("\tNo of tasks=")); Serial.println(--noOfTasks);
96+
}
97+
98+
/**
99+
Standard Arduino setup and loop methods
100+
*/
101+
void setup() {
102+
Serial.begin(115200);
103+
104+
randomSeed(analogRead(0) + analogRead(5));
105+
noOfTasks = 0;
106+
107+
Serial.println(F("Dynamic Task Creation/Destruction Example"));
108+
Serial.println();
109+
110+
Serial.print(F("Free mem=")); Serial.print(freeMemory());
111+
Serial.print(F("\tNo of tasks=")); Serial.println(noOfTasks);
112+
Serial.println();
113+
}
114+
115+
void loop() {
116+
ts.execute();
117+
if ( millis() > 5000 && noOfTasks == 0 ) {
118+
Serial.print(F("\tFree mem=")); Serial.println(freeMemory());
119+
while(1);
120+
}
121+
}

0 commit comments

Comments
 (0)