|
|
@@ -125,7 +125,9 @@
|
|
|
//
|
|
|
// v2.5.2:
|
|
|
// 2018-01-09 - _TASK_INLINE compilation directive making all methods declared "inline" (issue #42)
|
|
|
-
|
|
|
+//
|
|
|
+// v2.6.0:
|
|
|
+// 2018-01-30 - _TASK_TIMEOUT compilation directive: Task overall timeout functionality
|
|
|
|
|
|
|
|
|
#include <Arduino.h>
|
|
|
@@ -148,6 +150,7 @@
|
|
|
// #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 // Support for overall task timeout
|
|
|
|
|
|
#ifdef _TASK_MICRO_RES
|
|
|
|
|
|
@@ -167,7 +170,7 @@
|
|
|
#include <avr/power.h>
|
|
|
#endif // ARDUINO_ARCH_AVR
|
|
|
|
|
|
-#ifdef ARDUINO_ARCH_ESP8266
|
|
|
+#if defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_ESP32)
|
|
|
extern "C" {
|
|
|
#include "user_interface.h"
|
|
|
}
|
|
|
@@ -177,7 +180,7 @@ extern "C" {
|
|
|
#endif // _TASK_SLEEP_ON_IDLE_RUN
|
|
|
|
|
|
|
|
|
-#ifndef ARDUINO_ARCH_ESP8266
|
|
|
+#if !defined (ARDUINO_ARCH_ESP8266) && !defined (ARDUINO_ARCH_ESP32)
|
|
|
#ifdef _TASK_STD_FUNCTION
|
|
|
#error Support for std::function only for ESP8266 architecture
|
|
|
#undef _TASK_STD_FUNCTION
|
|
|
@@ -203,12 +206,11 @@ Task::Task( unsigned long aInterval, long aIterations, TaskCallback aCallback, S
|
|
|
reset();
|
|
|
set(aInterval, aIterations, aCallback, aOnEnable, aOnDisable);
|
|
|
if (aScheduler) aScheduler->addTask(*this);
|
|
|
-#ifdef _TASK_STATUS_REQUEST
|
|
|
- iStatusRequest = NULL;
|
|
|
-#endif // _TASK_STATUS_REQUEST
|
|
|
+
|
|
|
#ifdef _TASK_WDT_IDS
|
|
|
iTaskID = ++__task_id_counter;
|
|
|
#endif // _TASK_WDT_IDS
|
|
|
+
|
|
|
if (aEnable) enable();
|
|
|
}
|
|
|
|
|
|
@@ -232,7 +234,7 @@ Task::Task( TaskCallback aCallback, Scheduler* aScheduler, TaskOnEnable aOnEnabl
|
|
|
reset();
|
|
|
set(TASK_IMMEDIATE, TASK_ONCE, aCallback, aOnEnable, aOnDisable);
|
|
|
if (aScheduler) aScheduler->addTask(*this);
|
|
|
- iStatusRequest = NULL;
|
|
|
+
|
|
|
#ifdef _TASK_WDT_IDS
|
|
|
iTaskID = ++__task_id_counter;
|
|
|
#endif // _TASK_WDT_IDS
|
|
|
@@ -323,20 +325,31 @@ void Task::reset() {
|
|
|
iNext = NULL;
|
|
|
iScheduler = NULL;
|
|
|
iRunCounter = 0;
|
|
|
+
|
|
|
#ifdef _TASK_TIMECRITICAL
|
|
|
iOverrun = 0;
|
|
|
iStartDelay = 0;
|
|
|
#endif // _TASK_TIMECRITICAL
|
|
|
+
|
|
|
#ifdef _TASK_WDT_IDS
|
|
|
iControlPoint = 0;
|
|
|
#endif // _TASK_WDT_IDS
|
|
|
+
|
|
|
#ifdef _TASK_LTS_POINTER
|
|
|
iLTS = NULL;
|
|
|
#endif // _TASK_LTS_POINTER
|
|
|
+
|
|
|
#ifdef _TASK_STATUS_REQUEST
|
|
|
+ iStatusRequest = NULL;
|
|
|
iStatus.waiting = 0;
|
|
|
iMyStatusRequest.signalComplete();
|
|
|
#endif // _TASK_STATUS_REQUEST
|
|
|
+
|
|
|
+#ifdef _TASK_TIMEOUT
|
|
|
+ iTimeout = 0;
|
|
|
+ iStarttime = 0;
|
|
|
+ iStatus.timeout = false;
|
|
|
+#endif // _TASK_TIMEOUT
|
|
|
}
|
|
|
|
|
|
/** Explicitly set Task execution parameters
|
|
|
@@ -403,11 +416,16 @@ void Task::enable() {
|
|
|
iStatus.enabled = true;
|
|
|
}
|
|
|
iPreviousMillis = _TASK_TIME_FUNCTION() - (iDelay = iInterval);
|
|
|
+
|
|
|
+#ifdef _TASK_TIMEOUT
|
|
|
+ resetTimeout();
|
|
|
+#endif // _TASK_TIMEOUT
|
|
|
+
|
|
|
#ifdef _TASK_STATUS_REQUEST
|
|
|
if ( iStatus.enabled ) {
|
|
|
iMyStatusRequest.setWaiting();
|
|
|
}
|
|
|
-#endif
|
|
|
+#endif // _TASK_STATUS_REQUEST
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -428,6 +446,36 @@ void Task::enableDelayed(unsigned long aDelay) {
|
|
|
delay(aDelay);
|
|
|
}
|
|
|
|
|
|
+#ifdef _TASK_TIMEOUT
|
|
|
+void Task::setTimeout(unsigned long aTimeout, bool aReset) {
|
|
|
+ iTimeout = aTimeout;
|
|
|
+ if (aReset) resetTimeout();
|
|
|
+}
|
|
|
+
|
|
|
+void Task::resetTimeout() {
|
|
|
+ iStarttime = _TASK_TIME_FUNCTION();
|
|
|
+ iStatus.timeout = false;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned long Task::getTimeout() {
|
|
|
+ return iTimeout;
|
|
|
+}
|
|
|
+
|
|
|
+long Task::untilTimeout() {
|
|
|
+ if ( iTimeout ) {
|
|
|
+ return ( (long) (iStarttime + iTimeout) - (long) _TASK_TIME_FUNCTION() );
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+bool Task::timedOut() {
|
|
|
+ return iStatus.timeout;
|
|
|
+}
|
|
|
+
|
|
|
+#endif // _TASK_TIMEOUT
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
/** Delays Task for execution after a delay = aInterval (if task is enabled).
|
|
|
* leaves task enabled or disabled
|
|
|
* if aDelay is zero, delays for the original scheduling interval from now
|
|
|
@@ -479,17 +527,18 @@ bool Task::disable() {
|
|
|
/** Restarts task
|
|
|
* Task will run number of iterations again
|
|
|
*/
|
|
|
+
|
|
|
void Task::restart() {
|
|
|
- iIterations = iSetIterations;
|
|
|
- enable();
|
|
|
+ enable();
|
|
|
+ iIterations = iSetIterations;
|
|
|
}
|
|
|
|
|
|
/** Restarts task delayed
|
|
|
* Task will run number of iterations again
|
|
|
*/
|
|
|
void Task::restartDelayed(unsigned long aDelay) {
|
|
|
- iIterations = iSetIterations;
|
|
|
- enableDelayed(aDelay);
|
|
|
+ enableDelayed(aDelay);
|
|
|
+ iIterations = iSetIterations;
|
|
|
}
|
|
|
|
|
|
bool Task::isFirstIteration() { return (iRunCounter <= 1); }
|
|
|
@@ -542,9 +591,11 @@ void Scheduler::init() {
|
|
|
iFirst = NULL;
|
|
|
iLast = NULL;
|
|
|
iCurrent = NULL;
|
|
|
+
|
|
|
#ifdef _TASK_PRIORITY
|
|
|
iHighPriority = NULL;
|
|
|
#endif // _TASK_PRIORITY
|
|
|
+
|
|
|
#ifdef _TASK_SLEEP_ON_IDLE_RUN
|
|
|
allowSleep(true);
|
|
|
#endif // _TASK_SLEEP_ON_IDLE_RUN
|
|
|
@@ -618,6 +669,7 @@ void Scheduler::disableAll(bool aRecursive) {
|
|
|
current->disable();
|
|
|
current = current->iNext;
|
|
|
}
|
|
|
+
|
|
|
#ifdef _TASK_PRIORITY
|
|
|
if (aRecursive && iHighPriority) iHighPriority->disableAll(true);
|
|
|
#endif // _TASK_PRIORITY
|
|
|
@@ -633,9 +685,11 @@ void Scheduler::disableAll(bool aRecursive) {
|
|
|
current->enable();
|
|
|
current = current->iNext;
|
|
|
}
|
|
|
+
|
|
|
#ifdef _TASK_PRIORITY
|
|
|
if (aRecursive && iHighPriority) iHighPriority->enableAll(true);
|
|
|
#endif // _TASK_PRIORITY
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/** Sets scheduler for the higher priority tasks (support for layered task priority)
|
|
|
@@ -644,11 +698,13 @@ void Scheduler::disableAll(bool aRecursive) {
|
|
|
#ifdef _TASK_PRIORITY
|
|
|
void Scheduler::setHighPriorityScheduler(Scheduler* aScheduler) {
|
|
|
if (aScheduler != this) iHighPriority = aScheduler; // Setting yourself as a higher priority one will create infinite recursive call
|
|
|
+
|
|
|
#ifdef _TASK_SLEEP_ON_IDLE_RUN
|
|
|
if (iHighPriority) {
|
|
|
iHighPriority->allowSleep(false); // Higher priority schedulers should not do power management
|
|
|
}
|
|
|
#endif // _TASK_SLEEP_ON_IDLE_RUN
|
|
|
+
|
|
|
};
|
|
|
#endif // _TASK_PRIORITY
|
|
|
|
|
|
@@ -657,7 +713,7 @@ void Scheduler::setHighPriorityScheduler(Scheduler* aScheduler) {
|
|
|
void Scheduler::allowSleep(bool aState) {
|
|
|
iAllowSleep = aState;
|
|
|
|
|
|
-#ifdef ARDUINO_ARCH_ESP8266
|
|
|
+#if defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_ESP32)
|
|
|
wifi_set_sleep_type( iAllowSleep ? LIGHT_SLEEP_T : NONE_SLEEP_T );
|
|
|
#endif // ARDUINO_ARCH_ESP8266
|
|
|
|
|
|
@@ -710,6 +766,8 @@ void* Scheduler::currentLts() { return iCurrent->iLTS; }
|
|
|
bool Scheduler::isOverrun() { return (iCurrent->iOverrun < 0); }
|
|
|
#endif // _TASK_TIMECRITICAL
|
|
|
|
|
|
+
|
|
|
+
|
|
|
/** Makes one pass through the execution chain.
|
|
|
* Tasks are executed in the order they were added to the chain
|
|
|
* There is no concept of priority
|
|
|
@@ -720,7 +778,7 @@ bool Scheduler::execute() {
|
|
|
bool idleRun = true;
|
|
|
register unsigned long m, i; // millis, interval;
|
|
|
|
|
|
-#ifdef ARDUINO_ARCH_ESP8266
|
|
|
+#if defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_ESP32)
|
|
|
unsigned long t1 = micros();
|
|
|
unsigned long t2 = 0;
|
|
|
#endif // ARDUINO_ARCH_ESP8266
|
|
|
@@ -751,6 +809,15 @@ bool Scheduler::execute() {
|
|
|
m = _TASK_TIME_FUNCTION();
|
|
|
i = iCurrent->iInterval;
|
|
|
|
|
|
+#ifdef _TASK_TIMEOUT
|
|
|
+ // Disable task on a timeout
|
|
|
+ if ( iCurrent->iTimeout && (m - iCurrent->iStarttime > iCurrent->iTimeout) ) {
|
|
|
+ iCurrent->iStatus.timeout = true;
|
|
|
+ iCurrent->disable();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
#ifdef _TASK_STATUS_REQUEST
|
|
|
// If StatusRequest object was provided, and still pending, and task is waiting, this task should not run
|
|
|
// Otherwise, continue with execution as usual. Tasks waiting to StatusRequest need to be rescheduled according to
|
|
|
@@ -789,7 +856,7 @@ bool Scheduler::execute() {
|
|
|
}
|
|
|
} while (0); //guaranteed single run - allows use of "break" to exit
|
|
|
iCurrent = iCurrent->iNext;
|
|
|
-#ifdef ARDUINO_ARCH_ESP8266
|
|
|
+#if defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_ESP32)
|
|
|
yield();
|
|
|
#endif // ARDUINO_ARCH_ESP8266
|
|
|
}
|
|
|
@@ -816,10 +883,13 @@ bool Scheduler::execute() {
|
|
|
t2 = micros() - t1;
|
|
|
if (t2 < _TASK_ESP8266_DLY_THRESHOLD) delay(1); // ESP8266 implementation of delay() uses timers and yield
|
|
|
#endif // ARDUINO_ARCH_ESP8266
|
|
|
-
|
|
|
-#ifdef ARDUINO_ARCH_ESP32
|
|
|
-#endif // ARDUINO_ARCH_ESP32
|
|
|
-
|
|
|
+
|
|
|
+#ifdef ARDUINO_ARCH_ESP32
|
|
|
+//TODO Test this light sleep implementation for ESP32
|
|
|
+ esp_sleep_enable_timer_wakeup(1000); //1 ms
|
|
|
+ int ret= esp_light_sleep_start();
|
|
|
+#endif // ARDUINO_ARCH_ESP32
|
|
|
+
|
|
|
}
|
|
|
#endif // _TASK_SLEEP_ON_IDLE_RUN
|
|
|
|