Просмотр исходного кода

v2.6.0 - Timeout and ESP32 support
* _TASK_TIMEOUT support for Task overall timeout
* ESP32 support

BuildTools 8 лет назад
Родитель
Сommit
d2b71e8632
6 измененных файлов с 146 добавлено и 31 удалено
  1. 5 3
      README
  2. 7 1
      keywords.txt
  3. 1 1
      library.json
  4. 1 1
      library.properties
  5. 89 19
      src/TaskScheduler.h
  6. 43 6
      src/TaskSchedulerDeclarations.h

+ 5 - 3
README

@@ -79,11 +79,13 @@ Check out what TaskScheduler can do:
 
 Changelog:
 =========
+v2.6.0:
+   2018-01-30 - _TASK_TIMEOUT compilation directive: Task overall timeout functionality
+   2018-01-30 - Support for ESP32
+   
 v2.5.2:
-
    2018-01-09 - _TASK_INLINE compilation directive making all methods declared "inline" (issue #42)
-   2018-01-10 - _TASK_BARE_METAL compilation directive. Forward definition of arduino specific methods 
-                for bare metal implementations
+
 
 v2.5.1:
    2018-01-06 - support for IDLE sleep on Teensy boards (tested on Teensy 3.6)

+ 7 - 1
keywords.txt

@@ -71,6 +71,11 @@ getLtsPointer	KEYWORD2
 isOverrun	KEYWORD2
 setHighPriorityScheduler	KEYWORD2
 currentScheduler	KEYWORD2
+setTimeout	KEYWORD2
+resetTimeout	KEYWORD2
+getTimeout	KEYWORD2
+untilTimeout	KEYWORD2
+timedOut	KEYWORD2
 #######################################
 # Constants (LITERAL1)
 TASK_MILLISECOND	LITERAL1
@@ -80,6 +85,7 @@ TASK_HOUR	LITERAL1
 TASK_FOREVER	LITERAL1
 TASK_IMMEDIATE	LITERAL1
 TASK_ONCE	LITERAL1
+TASK_NOTIMEOUT  LITERAL1
 _TASK_TIMECRITICAL	LITERAL1
 _TASK_SLEEP_ON_IDLE_RUN	LITERAL1
 _TASK_STATUS_REQUEST	LITERAL1
@@ -90,7 +96,7 @@ _TASK_MICRO_RES	LITERAL1
 _TASK_STD_FUNCTION	LITERAL1
 _TASK_DEBUG	LITERAL1
 _TASK_INLINE	LITERAL1
-_TASK_BARE_METAL	LITERAL1
+_TASK_TIMEOUT	LITERAL1
 TaskCallback	LITERAL1
 TaskOnDisable	LITERAL1
 TaskOnEnable	LITERAL1

+ 1 - 1
library.json

@@ -16,7 +16,7 @@
       "maintainer": true
     }
   ],
-  "version": "2.5.2",
+  "version": "2.6.0",
   "frameworks": "arduino",
   "platforms": "*"
 }

+ 1 - 1
library.properties

@@ -1,5 +1,5 @@
 name=TaskScheduler
-version=2.5.2
+version=2.6.0
 author=Anatoli Arkhipenko <arkhipenko@hotmail.com>
 maintainer=Anatoli Arkhipenko <arkhipenko@hotmail.com>
 sentence=A light-weight cooperative multitasking library for arduino and esp8266 microcontrollers.

+ 89 - 19
src/TaskScheduler.h

@@ -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
 

+ 43 - 6
src/TaskSchedulerDeclarations.h

@@ -21,6 +21,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_DEBUG
     #define _TASK_SCOPE  public
@@ -32,6 +33,10 @@
 #define TASK_FOREVER         (-1)
 #define TASK_ONCE               1
 
+#ifdef _TASK_TIMEOUT  
+#define TASK_NOTIMEOUT			0
+#endif
+
 #ifdef _TASK_PRIORITY
     class Scheduler;
     extern Scheduler* iCurrentScheduler;
@@ -103,9 +108,15 @@ typedef bool (*TaskOnEnable)();
 typedef struct  {
     bool  enabled    : 1;           // indicates that task is enabled or not.
     bool  inonenable : 1;           // indicates that task execution is inside OnEnable method (preventing infinite loops)
+
 #ifdef _TASK_STATUS_REQUEST
-    uint8_t  waiting    : 2;           // indication if task is waiting on the status request
+    uint8_t  waiting : 2;        // indication if task is waiting on the status request
 #endif
+
+#ifdef _TASK_TIMEOUT
+    bool  timeout    : 1;           // indication if task is waiting on the status request
+#endif
+
 } __task_status;
 
 class Scheduler; 
@@ -115,18 +126,29 @@ class Task {
   friend class Scheduler;
   public:
     INLINE Task(unsigned long aInterval=0, long aIterations=0, TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, bool aEnable=false, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
+
 #ifdef _TASK_STATUS_REQUEST
     INLINE Task(TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
 #endif  // _TASK_STATUS_REQUEST
+
     INLINE ~Task();
 
+#ifdef _TASK_TIMEOUT 
+    INLINE void setTimeout(unsigned long aTimeout, bool aReset=false);
+    INLINE void resetTimeout(); 
+    INLINE unsigned long getTimeout();
+    INLINE long untilTimeout();
+    INLINE bool timedOut();
+#endif
+
     INLINE void enable();
     INLINE bool enableIfNot();
     INLINE void enableDelayed(unsigned long aDelay=0);
-    INLINE void delay(unsigned long aDelay=0);
-    INLINE void forceNextIteration(); 
     INLINE void restart();
     INLINE void restartDelayed(unsigned long aDelay=0);
+
+    INLINE void delay(unsigned long aDelay=0);
+    INLINE void forceNextIteration(); 
     INLINE bool disable();
     INLINE bool isEnabled();
     INLINE void set(unsigned long aInterval, long aIterations, TaskCallback aCallback,TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
@@ -174,10 +196,12 @@ class Task {
     volatile unsigned long    iInterval;             // execution interval in milliseconds (or microseconds). 0 - immediate
     volatile unsigned long    iDelay;                // actual delay until next execution (usually equal iInterval)
     volatile unsigned long    iPreviousMillis;       // previous invocation time (millis).  Next invocation = iPreviousMillis + iInterval.  Delayed tasks will "catch up" 
+
 #ifdef _TASK_TIMECRITICAL
     volatile long             iOverrun;              // negative if task is "catching up" to it's schedule (next invocation time is already in the past)
     volatile long             iStartDelay;           // actual execution of the task's callback method was delayed by this number of millis
 #endif  // _TASK_TIMECRITICAL
+
     volatile long             iIterations;           // number of iterations left. 0 - last iteration. -1 - infinite iterations
     long                      iSetIterations;        // number of iterations originally requested (for restarts)
     unsigned long             iRunCounter;           // current number of iteration (starting with 1). Resets on enable. 
@@ -186,17 +210,25 @@ class Task {
     TaskOnDisable             iOnDisable;            // pointer to the void OnDisable method
     Task                     *iPrev, *iNext;         // pointers to the previous and next tasks in the chain
     Scheduler                *iScheduler;            // pointer to the current scheduler
+
 #ifdef _TASK_STATUS_REQUEST
     StatusRequest            *iStatusRequest;        // pointer to the status request task is or was waiting on
     StatusRequest             iMyStatusRequest;      // internal Status request to let other tasks know of completion
 #endif  // _TASK_STATUS_REQUEST
+
 #ifdef _TASK_WDT_IDS
     unsigned int              iTaskID;               // task ID (for debugging and watchdog identification)
     unsigned int              iControlPoint;         // current control point within the callback method. Reset to 0 by scheduler at the beginning of each pass
 #endif  // _TASK_WDT_IDS
+
 #ifdef _TASK_LTS_POINTER
     void                     *iLTS;                  // pointer to task's local storage. Needs to be recast to appropriate type (usually a struct).
 #endif  // _TASK_LTS_POINTER
+
+#ifdef _TASK_TIMEOUT 
+	unsigned long            iTimeout;				 // Task overall timeout
+	unsigned long 			 iStarttime;			 // millis at task start time
+#endif // _TASK_TIMEOUT 
 };
 
 class Scheduler {
@@ -213,15 +245,19 @@ class Scheduler {
     INLINE void startNow(bool aRecursive = true);       // reset ALL active tasks to immediate execution NOW.
     INLINE Task& currentTask() ;
     INLINE long timeUntilNextIteration(Task& aTask);    // return number of ms until next iteration of a given Task
+
 #ifdef _TASK_SLEEP_ON_IDLE_RUN
     INLINE void allowSleep(bool aState = true);
 #endif  // _TASK_SLEEP_ON_IDLE_RUN
+
 #ifdef _TASK_LTS_POINTER
-    INLINE void* currentLts() ;
+    INLINE void* currentLts();
 #endif  // _TASK_LTS_POINTER
+
 #ifdef _TASK_TIMECRITICAL
-    INLINE bool isOverrun() ;
+    INLINE bool isOverrun();
 #endif  // _TASK_TIMECRITICAL
+
 #ifdef _TASK_PRIORITY
     INLINE void setHighPriorityScheduler(Scheduler* aScheduler);
     INLINE static Scheduler& currentScheduler() { return *(iCurrentScheduler); };
@@ -229,10 +265,11 @@ class Scheduler {
 
   _TASK_SCOPE:
     Task       *iFirst, *iLast, *iCurrent;        // pointers to first, last and current tasks in the chain
+
 #ifdef _TASK_SLEEP_ON_IDLE_RUN
     bool        iAllowSleep;                      // indication if putting avr to IDLE_SLEEP mode is allowed by the program at this time. 
-
 #endif  // _TASK_SLEEP_ON_IDLE_RUN
+
 #ifdef _TASK_PRIORITY
     Scheduler  *iHighPriority;                    // Pointer to a higher priority scheduler
 #endif  // _TASK_PRIORITY