diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/TaskScheduler.h | 119 |
1 files changed, 68 insertions, 51 deletions
diff --git a/src/TaskScheduler.h b/src/TaskScheduler.h index 8eea44b..e81212c 100644 --- a/src/TaskScheduler.h +++ b/src/TaskScheduler.h @@ -86,6 +86,7 @@ // // v2.1.0: // 2016-02-01 - support for microsecond resolution +// 2016-02-02 - added Scheduler baseline start time reset method: startNow() /* ============================================ Cooperative multitasking library code is placed under the MIT license @@ -114,7 +115,6 @@ THE SOFTWARE. #include <Arduino.h> - #ifndef _TASKSCHEDULER_H_ #define _TASKSCHEDULER_H_ @@ -141,22 +141,24 @@ THE SOFTWARE. #define _TASK_TIME_FUNCTION() millis() - #endif + #endif // _TASK_MICRO_RES + #ifdef _TASK_SLEEP_ON_IDLE_RUN #ifdef ARDUINO_ARCH_AVR #include <avr/sleep.h> #include <avr/power.h> -#endif +#endif // ARDUINO_ARCH_AVR #ifdef ARDUINO_ARCH_ESP8266 extern "C" { #include "user_interface.h" } -#endif +#define _TASK_ESP8266_DLY_THRESHOLD 200L +#endif // ARDUINO_ARCH_ESP8266 -#endif +#endif // _TASK_SLEEP_ON_IDLE_RUN #define TASK_IMMEDIATE 0 #define TASK_FOREVER (-1) @@ -175,7 +177,7 @@ extern "C" { #define TASK_MINUTE 60000000L #define TASK_HOUR 3600000000L -#endif +#endif // _TASK_MICRO_RES #ifdef _TASK_STATUS_REQUEST @@ -197,7 +199,7 @@ class StatusRequest { unsigned int iCount; // number of statuses to wait for. waiting for more that 65000 events seems unreasonable: unsigned int should be sufficient int iStatus; // status of the last completed request. negative = error; zero = OK; >positive = OK with a specific status }; -#endif +#endif // _TASK_STATUS_REQUEST typedef struct { @@ -213,7 +215,7 @@ class Scheduler; #ifdef _TASK_WDT_IDS static unsigned int __task_id_counter = 0; // global task ID counter for assiging task IDs automatically. -#endif +#endif // _TASK_WDT_IDS class Task { friend class Scheduler; @@ -221,7 +223,7 @@ class Task { Task(unsigned long aInterval=0, long aIterations=0, void (*aCallback)()=NULL, Scheduler* aScheduler=NULL, bool aEnable=false, bool (*aOnEnable)()=NULL, void (*aOnDisable)()=NULL); #ifdef _TASK_STATUS_REQUEST Task(void (*aCallback)()=NULL, Scheduler* aScheduler=NULL, bool (*aOnEnable)()=NULL, void (*aOnDisable)()=NULL); -#endif +#endif // _TASK_STATUS_REQUEST void enable(); bool enableIfNot(); @@ -244,24 +246,24 @@ class Task { #ifdef _TASK_TIMECRITICAL inline long getOverrun() { return iOverrun; } inline long getStartDelay() { return iStartDelay; } -#endif +#endif // _TASK_TIMECRITICAL inline bool isFirstIteration() { return (iRunCounter <= 1); } inline bool isLastIteration() { return (iIterations == 0); } #ifdef _TASK_STATUS_REQUEST void waitFor(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1); void waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval = 0, long aIterations = 1); inline StatusRequest* getStatusRequest() {return iStatusRequest; } -#endif +#endif // _TASK_STATUS_REQUEST #ifdef _TASK_WDT_IDS inline void setId(unsigned int aID) { iTaskID = aID; } inline unsigned int getId() { return iTaskID; } inline void setControlPoint(unsigned int aPoint) { iControlPoint = aPoint; } inline unsigned int getControlPoint() { return iControlPoint; } -#endif +#endif // _TASK_WDT_IDS #ifdef _TASK_LTS_POINTER inline void setLtsPointer(void *aPtr) { iLTS = aPtr; } inline void* getLtsPointer() { return iLTS; } -#endif +#endif // _TASK_LTS_POINTER private: void reset(); @@ -273,7 +275,7 @@ class Task { #ifdef _TASK_TIMECRITICAL volatile long iOverrun; // negative if task is "catching up" to it's schedule (next invocation time is already in the past) volatile long iStartDelay; // actual execution of the task's callback method was delayed by this number of millis -#endif +#endif // _TASK_TIMECRITICAL volatile long iIterations; // number of iterations left. 0 - last iteration. -1 - infinite iterations long iSetIterations; // number of iterations originally requested (for restarts) unsigned long iRunCounter; // current number of iteration (starting with 1). Resets on enable. @@ -284,20 +286,20 @@ class Task { Scheduler *iScheduler; // pointer to the current scheduler #ifdef _TASK_STATUS_REQUEST StatusRequest *iStatusRequest; // pointer to the status request task is or was waiting on -#endif +#endif // _TASK_STATUS_REQUEST #ifdef _TASK_WDT_IDS unsigned int iTaskID; // task ID (for debugging and watchdog identification) unsigned int iControlPoint; // current control point within the callback method. Reset to 0 by scheduler at the beginning of each pass -#endif +#endif // _TASK_WDT_IDS #ifdef _TASK_LTS_POINTER void *iLTS; // pointer to task's local storage. Needs to be recast to appropriate type (usually a struct). -#endif +#endif // _TASK_LTS_POINTER }; #ifdef _TASK_PRIORITY static Scheduler* iCurrentScheduler; -#endif +#endif // _TASK_PRIORITY class Scheduler { friend class Task; @@ -309,29 +311,30 @@ class Scheduler { void disableAll(bool aRecursive = true); void enableAll(bool aRecursive = true); bool execute(); // Returns true if at none of the tasks' callback methods was invoked (true if idle run) + void startNow(bool aRecursive = true); // reset ALL active tasks to immediate execution NOW. inline Task& currentTask() {return *iCurrent; } #ifdef _TASK_SLEEP_ON_IDLE_RUN void allowSleep(bool aState = true); -#endif +#endif // _TASK_SLEEP_ON_IDLE_RUN #ifdef _TASK_LTS_POINTER inline void* currentLts() {return iCurrent->iLTS; } -#endif +#endif // _TASK_LTS_POINTER #ifdef _TASK_TIMECRITICAL inline bool isOverrun() { return (iCurrent->iOverrun < 0); } -#endif +#endif // _TASK_TIMECRITICAL #ifdef _TASK_PRIORITY void setHighPriorityScheduler(Scheduler* aScheduler); static Scheduler& currentScheduler() { return *(iCurrentScheduler); }; -#endif +#endif // _TASK_PRIORITY private: Task *iFirst, *iLast, *iCurrent; // pointers to first, last and current tasks in the chain #ifdef _TASK_SLEEP_ON_IDLE_RUN bool iAllowSleep; // indication if putting avr to IDLE_SLEEP mode is allowed by the program at this time. -#endif +#endif // _TASK_SLEEP_ON_IDLE_RUN #ifdef _TASK_PRIORITY Scheduler *iHighPriority; // Pointer to a higher priority scheduler -#endif +#endif // _TASK_PRIORITY }; @@ -346,10 +349,10 @@ Task::Task( unsigned long aInterval, long aIterations, void (*aCallback)(), Sche if (aScheduler) aScheduler->addTask(*this); #ifdef _TASK_STATUS_REQUEST iStatusRequest = NULL; -#endif +#endif // _TASK_STATUS_REQUEST #ifdef _TASK_WDT_IDS iTaskID = ++__task_id_counter; -#endif +#endif // _TASK_WDT_IDS if (aEnable) enable(); } @@ -366,7 +369,7 @@ Task::Task( void (*aCallback)(), Scheduler* aScheduler, bool (*aOnEnable)(), voi iStatusRequest = NULL; #ifdef _TASK_WDT_IDS iTaskID = ++__task_id_counter; -#endif +#endif // _TASK_WDT_IDS } /** Signals completion of the StatusRequest by one of the participating events @@ -410,7 +413,7 @@ void Task::waitForDelayed(StatusRequest* aStatusRequest, unsigned long aInterval enable(); } } -#endif +#endif // _TASK_STATUS_REQUEST /** Resets (initializes) the task/ * Task is not enabled and is taken out @@ -428,16 +431,16 @@ void Task::reset() { #ifdef _TASK_TIMECRITICAL iOverrun = 0; iStartDelay = 0; -#endif +#endif // _TASK_TIMECRITICAL #ifdef _TASK_WDT_IDS iControlPoint = 0; -#endif +#endif // _TASK_WDT_IDS #ifdef _TASK_LTS_POINTER iLTS = NULL; -#endif +#endif // _TASK_LTS_POINTER #ifdef _TASK_STATUS_REQUEST iStatus.waiting = 0; -#endif +#endif // _TASK_STATUS_REQUEST } /** Explicitly set Task execution parameters @@ -580,10 +583,10 @@ void Scheduler::init() { iCurrent = NULL; #ifdef _TASK_PRIORITY iHighPriority = NULL; -#endif +#endif // _TASK_PRIORITY #ifdef _TASK_SLEEP_ON_IDLE_RUN allowSleep(true); -#endif +#endif // _TASK_SLEEP_ON_IDLE_RUN } /** Appends task aTask to the tail of the execution chain. @@ -651,8 +654,8 @@ void Scheduler::disableAll(bool aRecursive) { current = current->iNext; } #ifdef _TASK_PRIORITY - if (aRecursive && iHighPriority) iHighPriority->disableAll(aRecursive); -#endif + if (aRecursive && iHighPriority) iHighPriority->disableAll(true); +#endif // _TASK_PRIORITY } @@ -666,8 +669,8 @@ void Scheduler::disableAll(bool aRecursive) { current = current->iNext; } #ifdef _TASK_PRIORITY - if (aRecursive && iHighPriority) iHighPriority->enableAll(aRecursive); -#endif + if (aRecursive && iHighPriority) iHighPriority->enableAll(true); +#endif // _TASK_PRIORITY } /** Sets scheduler for the higher priority tasks (support for layered task priority) @@ -680,9 +683,9 @@ void Scheduler::setHighPriorityScheduler(Scheduler* aScheduler) { if (iHighPriority) { iHighPriority->allowSleep(false); // Higher priority schedulers should not do power management } -#endif +#endif // _TASK_SLEEP_ON_IDLE_RUN }; -#endif +#endif // _TASK_PRIORITY #ifdef _TASK_SLEEP_ON_IDLE_RUN @@ -691,12 +694,26 @@ void Scheduler::allowSleep(bool aState) { #ifdef ARDUINO_ARCH_ESP8266 wifi_set_sleep_type( iAllowSleep ? LIGHT_SLEEP_T : NONE_SLEEP_T ); -#endif +#endif // ARDUINO_ARCH_ESP8266 } -#endif +#endif // _TASK_SLEEP_ON_IDLE_RUN +void Scheduler::startNow( bool aRecursive ) { + unsigned long t = _TASK_TIME_FUNCTION(); + + iCurrent = iFirst; + while (iCurrent) { + if ( iCurrent->iStatus.enabled ) iCurrent->iPreviousMillis = t - iCurrent->iDelay; + iCurrent = iCurrent->iNext; + } + +#ifdef _TASK_PRIORITY + if (aRecursive && iHighPriority) iHighPriority->startNow( true ); +#endif // _TASK_PRIORITY +} + /** 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 @@ -710,7 +727,7 @@ bool Scheduler::execute() { #ifdef ARDUINO_ARCH_ESP8266 unsigned long t1 = micros(); unsigned long t2 = 0; -#endif +#endif // ARDUINO_ARCH_ESP8266 iCurrent = iFirst; @@ -720,7 +737,7 @@ bool Scheduler::execute() { // If scheduler for higher priority tasks is set, it's entire chain is executed on every pass of the base scheduler if (iHighPriority) idleRun = iHighPriority->execute() && idleRun; iCurrentScheduler = this; -#endif +#endif // _TASK_PRIORITY do { if ( iCurrent->iStatus.enabled ) { @@ -728,7 +745,7 @@ bool Scheduler::execute() { #ifdef _TASK_WDT_IDS // For each task the control points are initialized to avoid confusion because of carry-over: iCurrent->iControlPoint = 0; -#endif +#endif // _TASK_WDT_IDS // Disable task on last iteration: if (iCurrent->iIterations == 0) { @@ -752,7 +769,7 @@ bool Scheduler::execute() { } iCurrent->iStatus.waiting = 0; } -#endif +#endif // _TASK_STATUS_REQUEST if ( m - iCurrent->iPreviousMillis < iCurrent->iDelay ) break; @@ -766,7 +783,7 @@ bool Scheduler::execute() { unsigned long p = iCurrent->iPreviousMillis; iCurrent->iOverrun = (long) ( p + i - m ); iCurrent->iStartDelay = (long) ( m - p ); -#endif +#endif // _TASK_TIMECRITICAL iCurrent->iDelay = i; if ( iCurrent->iCallback ) { @@ -789,15 +806,15 @@ bool Scheduler::execute() { /* The program will continue from here after the timer timeout ~1 ms */ sleep_disable(); /* First thing to do is disable sleep. */ -#endif +#endif // ARDUINO_ARCH_AVR #ifdef ARDUINO_ARCH_ESP8266 // to do: find suitable sleep function for esp8266 t2 = micros() - t1; - if (t2 < 1000L) delay(1); // ESP8266 implementation of delay() uses timers and yield -#endif + if (t2 < _TASK_ESP8266_DLY_THRESHOLD) delay(1); // ESP8266 implementation of delay() uses timers and yield +#endif // ARDUINO_ARCH_ESP8266 } -#endif +#endif // _TASK_SLEEP_ON_IDLE_RUN return (idleRun); } |
