Explorar el Código

v3.5.0 - adjust(ms) method. platform.io example

Anatoli Arkhipenko hace 4 años
padre
commit
cb4ca5b524

+ 1 - 1
README.md

@@ -1,6 +1,6 @@
 # Task Scheduler
 ### Cooperative multitasking for Arduino, ESPx, STM32 and other microcontrollers
-#### Version 3.4.0: 2021-07-14 [Latest updates](https://github.com/arkhipenko/TaskScheduler/wiki/Latest-Updates)
+#### Version 3.5.0: 2021-11-01 [Latest updates](https://github.com/arkhipenko/TaskScheduler/wiki/Latest-Updates)
 
 [![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)
 

+ 5 - 0
examples/Scheduler_example27_PlatformIO/.gitignore

@@ -0,0 +1,5 @@
+.pio
+.vscode/.browse.c_cpp.db*
+.vscode/c_cpp_properties.json
+.vscode/launch.json
+.vscode/ipch

+ 7 - 0
examples/Scheduler_example27_PlatformIO/.vscode/extensions.json

@@ -0,0 +1,7 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ]
+}

+ 39 - 0
examples/Scheduler_example27_PlatformIO/include/README

@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

+ 12 - 0
examples/Scheduler_example27_PlatformIO/include/led.h

@@ -0,0 +1,12 @@
+#ifndef _TS27_LED_H
+#define _TS27_LED_H
+
+// LED_BUILTIN  13
+#if defined( ARDUINO_ARCH_ESP32 )
+#define LED_BUILTIN  23 // esp32 dev2 kit does not have LED
+#endif
+
+void LEDOff();
+void LEDOn();
+
+#endif //   _TS27_LED_H

+ 27 - 0
examples/Scheduler_example27_PlatformIO/include/main.h

@@ -0,0 +1,27 @@
+#ifndef _TS27_MAIN_H
+#define _TS27_MAIN_H
+
+#include <Arduino.h>
+
+#ifdef _DEBUG_
+#define _PP(a) Serial.print(a);
+#define _PL(a) Serial.println(a);
+#else
+#define _PP(a)
+#define _PL(a)
+#endif
+
+#define PERIOD1 500
+#define DURATION 10000
+
+#define PERIOD2 400
+
+#define PERIOD3 300
+
+#define PERIOD4 200
+
+#define PERIOD5 600
+
+#define PERIOD6 300
+
+#endif

+ 46 - 0
examples/Scheduler_example27_PlatformIO/lib/README

@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html

+ 38 - 0
examples/Scheduler_example27_PlatformIO/platformio.ini

@@ -0,0 +1,38 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:esp32dev]
+platform = espressif32
+board = esp32dev
+framework = arduino
+
+[env]
+lib_deps =
+    arkhipenko/TaskScheduler @ ^3.4.0
+    
+build_flags = 
+    ; -D _TASK_TIMECRITICAL       
+    -D _TASK_SLEEP_ON_IDLE_RUN  
+    -D _TASK_STATUS_REQUEST     
+    ; -D _TASK_WDT_IDS            
+    ; -D _TASK_LTS_POINTER        
+    ; -D _TASK_PRIORITY           
+    ; -D _TASK_MICRO_RES          
+    ; -D _TASK_STD_FUNCTION       
+    ; -D _TASK_DEBUG              
+    ; -D _TASK_INLINE             
+    ; -D _TASK_TIMEOUT            
+    ; -D _TASK_OO_CALLBACKS       
+    ; -D _TASK_EXPOSE_CHAIN       
+    ; -D _TASK_SCHEDULING_OPTIONS 
+    ; -D _TASK_DEFINE_MILLIS      
+    ; -D _TASK_EXTERNAL_TIME    
+    -D _DEBUG_
+    ; -D _TEST_  

+ 1 - 0
examples/Scheduler_example27_PlatformIO/src/TaskScheduler.cpp

@@ -0,0 +1 @@
+#include <TaskScheduler.h>

+ 11 - 0
examples/Scheduler_example27_PlatformIO/src/led.cpp

@@ -0,0 +1,11 @@
+#include <Arduino.h>
+#include "led.h"
+#include "main.h"
+
+void LEDOn() {
+  digitalWrite( LED_BUILTIN, HIGH );
+}
+
+void LEDOff() {
+  digitalWrite( LED_BUILTIN, LOW );
+}

+ 254 - 0
examples/Scheduler_example27_PlatformIO/src/main.cpp

@@ -0,0 +1,254 @@
+/*
+   Every example set must have a LED blink example
+   For this one the idea is to have as many ways to blink the LED
+   as I can think of. So, here we go.
+
+   Tested on:
+   - Arduino Nano
+   - ESP8266
+   - ESP32
+   - STM32 Maple Mini
+*/
+
+#include <TaskSchedulerDeclarations.h>
+
+#include "main.h"
+#include "led.h"
+
+// Scheduler
+Scheduler ts;
+
+/*
+   Approach 1: LED is driven by the boolean variable; false = OFF, true = ON
+*/
+void blink1CB();
+Task tBlink1 ( PERIOD1 * TASK_MILLISECOND, DURATION / PERIOD1, &blink1CB, &ts, true );
+
+/*
+   Approach 2: two callback methods: one turns ON, another turns OFF
+*/
+void blink2CB_ON();
+void blink2CB_OFF();
+Task tBlink2 ( PERIOD2 * TASK_MILLISECOND, DURATION / PERIOD2, &blink2CB_ON, &ts, false );
+
+/*
+   Approach 3: Use RunCounter
+*/
+void blink3CB();
+Task tBlink3 (PERIOD3 * TASK_MILLISECOND, DURATION / PERIOD3, &blink3CB, &ts, false);
+
+/*
+   Approach 4: Use status request objects to pass control from one task to the other
+*/
+bool blink41OE();
+void blink41();
+void blink42();
+void blink42OD();
+Task tBlink4On  ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink41, &ts, false, &blink41OE );
+Task tBlink4Off ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink42, &ts, false, NULL, &blink42OD );
+
+
+/*
+   Approach 5: Two interleaving tasks
+*/
+bool blink51OE();
+void blink51();
+void blink52();
+void blink52OD();
+Task tBlink5On  ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink51, &ts, false, &blink51OE );
+Task tBlink5Off ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink52, &ts, false, NULL, &blink52OD );
+
+
+/*
+   Approach 6: RunCounter-based with random intervals
+*/
+void blink6CB();
+bool blink6OE();
+void blink6OD();
+Task tBlink6 ( PERIOD6 * TASK_MILLISECOND, DURATION / PERIOD6, &blink6CB, &ts, false, &blink6OE, &blink6OD );
+
+void setup() {
+  // put your setup code here, to run once:
+#if defined(_DEBUG_) || defined(_TEST_)
+  Serial.begin(115200);
+  delay(TASK_SECOND);
+  _PL("TaskScheduler Blink example");
+  _PL("Blinking for 10 seconds using various techniques\n");
+  delay(2 * TASK_SECOND);
+#endif
+  pinMode(LED_BUILTIN, OUTPUT);
+}
+
+void loop() {
+  ts.execute();
+}
+
+// === 1 =======================================
+bool LED_state = false;
+void blink1CB() {
+  if ( tBlink1.isFirstIteration() ) {
+    _PP(millis());
+    _PL(": Blink1 - simple flag driven");
+    LED_state = false;
+  }
+
+  if ( LED_state ) {
+    LEDOff();
+    LED_state = false;
+  }
+  else {
+    LEDOn();
+    LED_state = true;
+  }
+
+  if ( tBlink1.isLastIteration() ) {
+    tBlink2.restartDelayed( 2 * TASK_SECOND );
+    LEDOff();
+  }
+}
+
+
+// === 2 ======================================
+void blink2CB_ON() {
+  if ( tBlink2.isFirstIteration() ) {
+    _PP(millis());
+    _PL(": Blink2 - 2 callback methods");
+  }
+
+  LEDOn();
+  tBlink2.setCallback( &blink2CB_OFF );
+
+  if ( tBlink2.isLastIteration() ) {
+    tBlink3.restartDelayed( 2 * TASK_SECOND );
+    LEDOff();
+  }
+}
+
+
+void blink2CB_OFF() {
+
+  LEDOff();
+  tBlink2.setCallback( &blink2CB_ON );
+
+  if ( tBlink2.isLastIteration() ) {
+    tBlink3.restartDelayed( 2 * TASK_SECOND );
+    LEDOff();
+  }
+}
+
+
+// === 3 =====================================
+void blink3CB() {
+  if ( tBlink3.isFirstIteration() ) {
+    _PP(millis());
+    _PL(": Blink3 - Run Counter driven");
+  }
+
+  if ( tBlink3.getRunCounter() & 1 ) {
+    LEDOn();
+  }
+  else {
+    LEDOff();
+  }
+
+  if ( tBlink3.isLastIteration() ) {
+    tBlink4On.setOnEnable( &blink41OE );
+    tBlink4On.restartDelayed( 2 * TASK_SECOND );
+    LEDOff();
+  }
+}
+
+
+// === 4 =============================================
+int counter = 0;
+bool blink41OE() {
+  _PP(millis());
+  _PL(": Blink4 - Internal status request based");
+  counter = 0;
+  tBlink4On.setOnEnable( NULL );
+  return true;
+}
+
+void blink41() {
+  //  _PP(millis());
+  //  _PL(": blink41");
+  LEDOn();
+  StatusRequest* r = tBlink4On.getInternalStatusRequest();
+  tBlink4Off.waitForDelayed( r );
+  counter++;
+}
+
+void blink42() {
+  //  _PP(millis());
+  //  _PL(": blink42");
+  LEDOff();
+  StatusRequest* r = tBlink4Off.getInternalStatusRequest();
+  tBlink4On.waitForDelayed( r );
+  counter++;
+}
+
+
+void blink42OD() {
+  if ( counter >= DURATION / PERIOD4 ) {
+    tBlink4On.disable();
+    tBlink4Off.disable();
+
+    tBlink5On.setOnEnable( &blink51OE );
+    tBlink5On.restartDelayed( 2 * TASK_SECOND );
+    tBlink5Off.restartDelayed( 2 * TASK_SECOND + PERIOD5 / 2 );
+    LEDOff();
+  }
+}
+
+
+// === 5 ==========================================
+bool blink51OE() {
+  _PP(millis());
+  _PL(": Blink5 - Two interleaving tasks");
+  tBlink5On.setOnEnable( NULL );
+  return true;
+}
+void blink51() {
+  //  _PP(millis());
+  //  _PL(": blink51");
+  LEDOn();
+}
+void blink52() {
+  //  _PP(millis());
+  //  _PL(": blink52");
+  LEDOff();
+}
+void blink52OD() {
+  tBlink6.restartDelayed( 2 * TASK_SECOND );
+  LEDOff();
+}
+
+
+// === 6 ============================================
+long interval6 = 0;
+bool blink6OE() {
+  _PP(millis());
+  _PP(": Blink6 - RunCounter + Random ON interval = ");
+  interval6 = random( 100, 901 );
+  tBlink6.setInterval( interval6 );
+  _PL( interval6 );
+  tBlink6.delay( 2 * TASK_SECOND );
+
+  return true;
+}
+
+void blink6CB() {
+  if ( tBlink6.getRunCounter() & 1 ) {
+    LEDOn();
+    tBlink6.setInterval( interval6 );
+  }
+  else {
+    LEDOff();
+    tBlink6.setInterval( TASK_SECOND - interval6 );
+  }
+}
+
+void blink6OD() {
+  tBlink1.restartDelayed( 2 * TASK_SECOND );
+  LEDOff();
+}

+ 11 - 0
examples/Scheduler_example27_PlatformIO/test/README

@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Unit Testing and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/page/plus/unit-testing.html

+ 1 - 0
keywords.txt

@@ -16,6 +16,7 @@ Task	KEYWORD1
 
 abort	KEYWORD2
 addTask	KEYWORD2
+adjust	KEYWORD2
 allowSleep	KEYWORD2
 Callback	KEYWORD2
 cancel	KEYWORD2

+ 1 - 1
library.json

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

+ 1 - 1
library.properties

@@ -1,5 +1,5 @@
 name=TaskScheduler
-version=3.4.0
+version=3.5.0
 author=Anatoli Arkhipenko <arkhipenko@hotmail.com>
 maintainer=Anatoli Arkhipenko <arkhipenko@hotmail.com>
 sentence=Cooperative multitasking for Arduino, ESPx, STM32 and other microcontrollers.

+ 23 - 3
src/TaskScheduler.h

@@ -199,6 +199,13 @@
 // v3.4.0:
 //    2021-07-14 - feature: ability to Enable/Disable and Pause/Resume scheduling 
 //               - feature: optional use of external millis/micros methods 
+//
+// v3.5.0:
+//    2021-11-01 - feature: adjust(long aInterval) method - adjust execution schedule: 
+//                 + aInterval - shift schedule forward (later)
+//                 - aInterval - shift schedule backwards (earlier)
+//
+//
 
 
 
@@ -643,11 +650,24 @@ bool Task::timedOut() {
  * if aDelay is zero, delays for the original scheduling interval from now
  */
 void Task::delay(unsigned long aDelay) {
-//  if (!aDelay) aDelay = iInterval;
     iDelay = aDelay ? aDelay : iInterval;
-    iPreviousMillis = _TASK_TIME_FUNCTION(); // - iInterval + aDelay;
+    iPreviousMillis = _TASK_TIME_FUNCTION(); 
+}
+
+/** Adjusts Task execution with aInterval (if task is enabled).
+ */
+void Task::adjust(long aInterval) {
+    if ( aInterval == 0 ) return;  //  nothing to do for a zero
+    if ( aInterval < 0 ) {
+      iPreviousMillis += aInterval;
+    }
+    else {
+      iDelay += aInterval;  //  we have to adjust delay because adjusting iPreviousMillis might push
+                            //  it into the future beyond current millis() and cause premature trigger
+    }
 }
 
+
 /** Schedules next iteration of Task for execution immediately (if enabled)
  * leaves task enabled or disabled
  * Task's original schedule is shifted, and all subsequent iterations will continue from this point in time
@@ -969,7 +989,7 @@ long Scheduler::timeUntilNextIteration(Task& aTask) {
     if ( !aTask.isEnabled() )
         return (-1);    // cannot be determined
 
-    long d = (long) aTask.iDelay - ( (long) ((_TASK_TIME_FUNCTION() - aTask.iPreviousMillis)) );
+    long d = (long) aTask.iDelay - ( (long) (_TASK_TIME_FUNCTION() - aTask.iPreviousMillis) );
 
     if ( d < 0 )
         return (0); // Task will run as soon as possible

+ 3 - 2
src/TaskSchedulerDeclarations.h

@@ -100,8 +100,8 @@ class StatusRequest {
     INLINE void signalComplete(int aStatus = 0);
     INLINE bool pending();
     INLINE bool completed();
-    INLINE int getStatus();
-    INLINE int getCount();
+    INLINE int  getStatus();
+    INLINE int  getCount();
     
 #ifdef _TASK_TIMEOUT
     INLINE void setTimeout(unsigned long aTimeout) { iTimeout = aTimeout; };
@@ -193,6 +193,7 @@ class Task {
     INLINE bool restartDelayed(unsigned long aDelay=0);
 
     INLINE void delay(unsigned long aDelay=0);
+    INLINE void adjust(long aInterval);
     INLINE void forceNextIteration();
     INLINE bool disable();
     INLINE void abort();