Преглед изворни кода

v3.0.0 MAJOR RELEASE
* Support for dynamic callback methods binding (_TASK_OO_CALLBACKS compile directive)

BuildTools пре 7 година
родитељ
комит
7d33d85287

+ 5 - 1
README

@@ -1,5 +1,5 @@
 Task Scheduler – cooperative multitasking for Arduino and ESP8266 microcontrollers
-Version 2.6.1 2018-03-15
+Version 3.0.0 2018-03-15
 
 If you find TaskScheduler useful for your Arduino project, please drop me an email: arkhipenko@hotmail.com
 ----------------------------------------------------------------------------------------------------------
@@ -17,6 +17,7 @@ OVERVIEW:
  9. Layered task prioritization
 10. Support for std::functions (ESP8266 only)
 11. Overall task timeout
+12. Static and dynamic callback method binding
 
 Scheduling overhead: between 15 and 18 microseconds per scheduling pass (check the benchmark example).
 
@@ -81,6 +82,9 @@ Check out what TaskScheduler can do:
 
 Changelog:
 =========
+v3.0.0: MAJOR RELEASE
+   2018-03-15 - Optional Dynamic callback method binding (_TASK_OO_CALLBACKS compilation directive).
+
 v2.6.1:
    2018-02-13 - Bug: Support for task self-destruction in the OnDisable method.
                 Example 19: dynamic task creation and destruction.

+ 1 - 0
README.md

@@ -15,6 +15,7 @@ A lightweight implementation of cooperative multitasking (task scheduling) suppo
 9. Support for layered task prioritization
 10. Support for `std::functions` (`ESP8266` only)
 11. Overall task timeout
+12. Static and dynamic callback method binding
 
 Scheduling overhead: between `15` and `18` microseconds per scheduling pass (Arduino UNO rev 3 @ `16MHz` clock, single scheduler w/o prioritization)
 

+ 53 - 0
examples/Scheduler_example21_OO_Callbacks/Calculator.cpp

@@ -0,0 +1,53 @@
+#include "Calculator.h"
+#include "SuperSensor.h"
+#include <MemoryFree.h>
+
+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
+  Serial.print("Free mem = "); Serial.println(freeMemory()); Serial.println();
+}
+
+void Calculator::reportDistance(long aD) {
+  if (distance < aD) distance = aD;
+}
+

+ 34 - 0
examples/Scheduler_example21_OO_Callbacks/Calculator.h

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

+ 65 - 0
examples/Scheduler_example21_OO_Callbacks/Scheduler_example21_OO_Callbacks.ino

@@ -0,0 +1,65 @@
+/**
+    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
+
+       This sketch uses a FreeMemory library: https://github.com/McNeight/MemoryFree
+*/
+
+
+#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;//(&hts, &ts);
+Ticker*     tCycle; //(&hts, (Task*) &tCalculate, &measure);
+
+int pins[] = { 1, 9, 3, 7, 5, 6, 4, 8, 2, 10 };
+
+
+/** 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 = new Calculator (&hts, &ts);
+  tCycle     = new Ticker (&hts, (Task*) &tCalculate, &measure);
+
+  tCalculate->setTimeout(1 * TASK_SECOND);
+  tCycle->enable();
+}
+
+void loop() {
+  ts.execute();
+}

+ 84 - 0
examples/Scheduler_example21_OO_Callbacks/SuperSensor.cpp

@@ -0,0 +1,84 @@
+#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();
+    return true;
+  }
+  return false;
+}
+
+void SuperSensor::OnDisable() {
+  int i = getId();
+
+  Serial.print(millis()); Serial.print(":\t");
+  Serial.print("SDisable: TaskID=");
+  Serial.println(i);
+
+  stop();
+
+  delete this;
+}

+ 44 - 0
examples/Scheduler_example21_OO_Callbacks/SuperSensor.h

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

+ 20 - 0
examples/Scheduler_example21_OO_Callbacks/Ticker.cpp

@@ -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);
+}
+

+ 28 - 0
examples/Scheduler_example21_OO_Callbacks/Ticker.h

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

+ 4 - 0
keywords.txt

@@ -76,6 +76,9 @@ resetTimeout	KEYWORD2
 getTimeout	KEYWORD2
 untilTimeout	KEYWORD2
 timedOut	KEYWORD2
+Callback	KEYWORD2
+OnEnable	KEYWORD2
+OnDisable	KEYWORD2
 #######################################
 # Constants (LITERAL1)
 TASK_MILLISECOND	LITERAL1
@@ -97,6 +100,7 @@ _TASK_STD_FUNCTION	LITERAL1
 _TASK_DEBUG	LITERAL1
 _TASK_INLINE	LITERAL1
 _TASK_TIMEOUT	LITERAL1
+_TASK_OO_CALLBACKS	LITERAL1
 TaskCallback	LITERAL1
 TaskOnDisable	LITERAL1
 TaskOnEnable	LITERAL1

+ 1 - 1
library.json

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

+ 2 - 2
library.properties

@@ -1,9 +1,9 @@
 name=TaskScheduler
-version=2.6.1
+version=3.0.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.
-paragraph=Supports: periodic task execution (with dynamic execution period in milliseconds or microseconds – frequency of execution), number of iterations (limited or infinite number of iterations), execution of tasks in predefined sequence, dynamic change of task execution parameters (frequency, number of iterations, callback methods), power saving via entering IDLE sleep mode when tasks are not scheduled to run, event-driven task invocation via Status Request object, task IDs and Control Points for error handling and watchdog timer, Local Task Storage pointer (allowing use of same callback code for multiple tasks), layered task prioritization, std::functions (esp8266, esp32 only), overall task timeout.
+paragraph=Supports: periodic task execution (with dynamic execution period in milliseconds or microseconds – frequency of execution), number of iterations (limited or infinite number of iterations), execution of tasks in predefined sequence, dynamic change of task execution parameters (frequency, number of iterations, callback methods), power saving via entering IDLE sleep mode when tasks are not scheduled to run, event-driven task invocation via Status Request object, task IDs and Control Points for error handling and watchdog timer, Local Task Storage pointer (allowing use of same callback code for multiple tasks), layered task prioritization, std::functions (esp8266, esp32 only), overall task timeout, static and dynamic callback method binding.
 category=Timing
 url=https://github.com/arkhipenko/TaskScheduler.git
 architectures=*

+ 71 - 5
src/TaskScheduler.h

@@ -157,8 +157,9 @@
 // #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_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 callbacks via inheritance
 
  #ifdef _TASK_MICRO_RES
 
@@ -215,9 +216,16 @@ extern "C" {
 /** Constructor, uses default values for the parameters
  * so could be called with no parameters.
  */
+#ifdef _TASK_OO_CALLBACKS
+Task::Task( unsigned long aInterval, long aIterations, Scheduler* aScheduler, bool aEnable ) {
+    reset();
+    set(aInterval, aIterations);
+#else
 Task::Task( unsigned long aInterval, long aIterations, TaskCallback aCallback, Scheduler* aScheduler, bool aEnable, TaskOnEnable aOnEnable, TaskOnDisable aOnDisable ) {
     reset();
     set(aInterval, aIterations, aCallback, aOnEnable, aOnDisable);
+#endif
+
     if (aScheduler) aScheduler->addTask(*this);
 
 #ifdef _TASK_WDT_IDS
@@ -243,9 +251,17 @@ Task::~Task() {
 /** Constructor with reduced parameter list for tasks created for
  *  StatusRequest only triggering (always immediate and only 1 iteration)
  */
+
+#ifdef _TASK_OO_CALLBACKS
+Task::Task( Scheduler* aScheduler ) {
+    reset();
+    set(TASK_IMMEDIATE, TASK_ONCE);
+#else
 Task::Task( TaskCallback aCallback, Scheduler* aScheduler, TaskOnEnable aOnEnable, TaskOnDisable aOnDisable ) {
     reset();
     set(TASK_IMMEDIATE, TASK_ONCE, aCallback, aOnEnable, aOnDisable);
+#endif // _TASK_OO_CALLBACKS
+
     if (aScheduler) aScheduler->addTask(*this);
 
 #ifdef _TASK_WDT_IDS
@@ -319,12 +335,21 @@ long Task::getIterations() { return iIterations; }
 
 unsigned long Task::getRunCounter() { return iRunCounter; }
 
-void Task::setCallback(TaskCallback aCallback) { iCallback = aCallback; }
+#ifdef _TASK_OO_CALLBACKS
 
-void Task::setOnEnable(TaskOnEnable aCallback) { iOnEnable = aCallback; }
+// bool Task::Callback() { return true; }
+bool Task::OnEnable() { return true; }
+void Task::OnDisable() { }
+
+#else
 
+void Task::setCallback(TaskCallback aCallback) { iCallback = aCallback; }
+void Task::setOnEnable(TaskOnEnable aCallback) { iOnEnable = aCallback; }
 void Task::setOnDisable(TaskOnDisable aCallback) { iOnDisable = aCallback; }
 
+#endif // _TASK_OO_CALLBACKS
+
+
 /** Resets (initializes) the task/
  * Task is not enabled and is taken out
  * out of the execution chain as a result
@@ -372,12 +397,18 @@ void Task::reset() {
  * @param aOnEnable - pointer to the callback method which is called on enable()
  * @param aOnDisable - pointer to the callback method which is called on disable()
  */
+
+#ifdef _TASK_OO_CALLBACKS
+void Task::set(unsigned long aInterval, long aIterations) {
+#else
 void Task::set(unsigned long aInterval, long aIterations, TaskCallback aCallback, TaskOnEnable aOnEnable, TaskOnDisable aOnDisable) {
-    setInterval(aInterval);
-    iSetIterations = iIterations = aIterations;
     iCallback = aCallback;
     iOnEnable = aOnEnable;
     iOnDisable = aOnDisable;
+#endif // _TASK_OO_CALLBACKS
+
+    setInterval(aInterval);
+    iSetIterations = iIterations = aIterations;
 }
 
 /** Sets number of iterations for the task
@@ -388,6 +419,8 @@ void Task::setIterations(long aIterations) {
     iSetIterations = iIterations = aIterations;
 }
 
+#ifndef _TASK_OO_CALLBACKS
+
 /** Prepare task for next step iteration following yielding of control to the scheduler
  * @param aCallback - pointer to the callback method for the next step
  */
@@ -409,6 +442,8 @@ void Task::yieldOnce (TaskCallback aCallback) {
     yield(aCallback);
     iIterations = 1;
 }
+#endif // _TASK_OO_CALLBACKS
+
 
 /** Enables the task
  *  schedules it for execution as soon as possible,
@@ -417,6 +452,17 @@ void Task::yieldOnce (TaskCallback aCallback) {
 void Task::enable() {
     if (iScheduler) { // activation without active scheduler does not make sense
         iRunCounter = 0;
+
+#ifdef _TASK_OO_CALLBACKS
+        if ( !iStatus.inonenable ) {
+            Task *current = iScheduler->iCurrent;
+            iScheduler->iCurrent = this;
+            iStatus.inonenable = true;      // Protection against potential infinite loop
+            iStatus.enabled = OnEnable();
+            iStatus.inonenable = false;     // Protection against potential infinite loop
+            iScheduler->iCurrent = current;
+        }
+#else
         if ( iOnEnable && !iStatus.inonenable ) {
             Task *current = iScheduler->iCurrent;
             iScheduler->iCurrent = this;
@@ -428,6 +474,8 @@ void Task::enable() {
         else {
             iStatus.enabled = true;
         }
+#endif // _TASK_OO_CALLBACKS
+
         iPreviousMillis = _TASK_TIME_FUNCTION() - (iDelay = iInterval);
 
 #ifdef _TASK_TIMEOUT
@@ -521,14 +569,26 @@ void Task::setInterval (unsigned long aInterval) {
  * Task will no longer be executed by the scheduler
  * Returns status of the task before disable was called (i.e., if the task was already disabled)
  */
+
 bool Task::disable() {
     bool previousEnabled = iStatus.enabled;
     iStatus.enabled = false;
     iStatus.inonenable = false;
+
+#ifdef _TASK_OO_CALLBACKS
+    if (previousEnabled) {
+#else
     if (previousEnabled && iOnDisable) {
+#endif // _TASK_OO_CALLBACKS
+
         Task *current = iScheduler->iCurrent;
         iScheduler->iCurrent = this;
+#ifdef _TASK_OO_CALLBACKS
+        OnDisable();
+#else
         iOnDisable();
+#endif // _TASK_OO_CALLBACKS
+
         iScheduler->iCurrent = current;
     }
 #ifdef _TASK_STATUS_REQUEST
@@ -876,10 +936,16 @@ bool Scheduler::execute() {
 #endif  // _TASK_TIMECRITICAL
 
                 iCurrent->iDelay = i;
+
+#ifdef _TASK_OO_CALLBACKS
+                idleRun = !iCurrent->Callback();
+#else
                 if ( iCurrent->iCallback ) {
                     iCurrent->iCallback();
                     idleRun = false;
                 }
+#endif // _TASK_OO_CALLBACKS
+
             }
         } while (0);    //guaranteed single run - allows use of "break" to exit
         iCurrent = nextTask;

+ 43 - 16
src/TaskSchedulerDeclarations.h

@@ -1,7 +1,7 @@
 // Cooperative multitasking library for Arduino
 // Copyright (c) 2015-2017 Anatoli Arkhipenko
 
-#include <stddef.h> 
+#include <stddef.h>
 #include <stdint.h>
 
 #ifndef _TASKSCHEDULERDECLARATIONS_H_
@@ -10,9 +10,9 @@
 // ----------------------------------------
 // The following "defines" control library functionality at compile time,
 // and should be used in the main sketch depending on the functionality required
-// 
+//
 // #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_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
@@ -21,7 +21,8 @@
 // #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_TIMEOUT           // Support for overall task timeout
+// #define _TASK_OO_CALLBACKS      // Support for dynamic callback method binding
 
 #ifdef _TASK_DEBUG
     #define _TASK_SCOPE  public
@@ -33,7 +34,7 @@
 #define TASK_FOREVER         (-1)
 #define TASK_ONCE               1
 
-#ifdef _TASK_TIMEOUT  
+#ifdef _TASK_TIMEOUT
 #define TASK_NOTIMEOUT			0
 #endif
 
@@ -48,7 +49,7 @@
 #endif
 
 
-#ifdef _TASK_INLINE	
+#ifdef _TASK_INLINE
 #define INLINE	inline
 #else
 #define INLINE
@@ -119,23 +120,32 @@ typedef struct  {
 
 } __task_status;
 
-class Scheduler; 
+class Scheduler;
 
 
 class Task {
   friend class Scheduler;
   public:
+
+#ifdef _TASK_OO_CALLBACKS
+    INLINE Task(unsigned long aInterval=0, long aIterations=0, Scheduler* aScheduler=NULL, bool aEnable=false);
+#else
     INLINE Task(unsigned long aInterval=0, long aIterations=0, TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, bool aEnable=false, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
+#endif // _TASK_OO_CALLBACKS
 
 #ifdef _TASK_STATUS_REQUEST
+#ifdef _TASK_OO_CALLBACKS
+    INLINE Task(Scheduler* aScheduler=NULL);
+#else
     INLINE Task(TaskCallback aCallback=NULL, Scheduler* aScheduler=NULL, TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
+#endif // _TASK_OO_CALLBACKS
 #endif  // _TASK_STATUS_REQUEST
 
     INLINE ~Task();
 
-#ifdef _TASK_TIMEOUT 
+#ifdef _TASK_TIMEOUT
     INLINE void setTimeout(unsigned long aTimeout, bool aReset=false);
-    INLINE void resetTimeout(); 
+    INLINE void resetTimeout();
     INLINE unsigned long getTimeout();
     INLINE long untilTimeout();
     INLINE bool timedOut();
@@ -148,23 +158,36 @@ class Task {
     INLINE void restartDelayed(unsigned long aDelay=0);
 
     INLINE void delay(unsigned long aDelay=0);
-    INLINE void forceNextIteration(); 
+    INLINE void forceNextIteration();
     INLINE bool disable();
     INLINE bool isEnabled();
+
+#ifdef _TASK_OO_CALLBACKS
+    INLINE void set(unsigned long aInterval, long aIterations);
+#else
     INLINE void set(unsigned long aInterval, long aIterations, TaskCallback aCallback,TaskOnEnable aOnEnable=NULL, TaskOnDisable aOnDisable=NULL);
+#endif // _TASK_OO_CALLBACKS
     INLINE void setInterval(unsigned long aInterval);
     INLINE unsigned long getInterval();
     INLINE void setIterations(long aIterations);
     INLINE long getIterations();
     INLINE unsigned long getRunCounter() ;
+
+#ifdef _TASK_OO_CALLBACKS
+    virtual INLINE bool Callback() =0;  // return true if run was "productive - this will disable sleep on the idle run for next pass
+    virtual INLINE bool OnEnable();  // return true if task should be enabled, false if it should remain disabled
+    virtual INLINE void OnDisable();
+#else
     INLINE void setCallback(TaskCallback aCallback) ;
     INLINE void setOnEnable(TaskOnEnable aCallback) ;
     INLINE void setOnDisable(TaskOnDisable aCallback) ;
     INLINE void yield(TaskCallback aCallback);
     INLINE void yieldOnce(TaskCallback aCallback);
+#endif // _TASK_OO_CALLBACKS
+
     INLINE bool isFirstIteration() ;
     INLINE bool isLastIteration() ;
-    
+
 #ifdef _TASK_TIMECRITICAL
     INLINE long getOverrun() ;
     INLINE long getStartDelay() ;
@@ -195,7 +218,7 @@ class Task {
     volatile __task_status    iStatus;
     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" 
+    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)
@@ -204,10 +227,14 @@ class Task {
 
     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. 
+    unsigned long             iRunCounter;           // current number of iteration (starting with 1). Resets on enable.
+
+#ifndef _TASK_OO_CALLBACKS
     TaskCallback              iCallback;             // pointer to the void callback method
     TaskOnEnable              iOnEnable;             // pointer to the bolol OnEnable callback method
     TaskOnDisable             iOnDisable;            // pointer to the void OnDisable method
+#endif // _TASK_OO_CALLBACKS
+
     Task                     *iPrev, *iNext;         // pointers to the previous and next tasks in the chain
     Scheduler                *iScheduler;            // pointer to the current scheduler
 
@@ -225,10 +252,10 @@ class Task {
     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 
+#ifdef _TASK_TIMEOUT
 	unsigned long            iTimeout;				 // Task overall timeout
 	unsigned long 			 iStarttime;			 // millis at task start time
-#endif // _TASK_TIMEOUT 
+#endif // _TASK_TIMEOUT
 };
 
 class Scheduler {
@@ -267,7 +294,7 @@ class Scheduler {
     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. 
+    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