arkadiusz binder пре 5 година
родитељ
комит
a0e30d3bd4
36 измењених фајлова са 2909 додато и 0 уклоњено
  1. 165 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/LICENSE
  2. 231 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/README.md
  3. 42 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat1/Beat1.ino
  4. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat1/led.h
  5. 37 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat2/Beat2.ino
  6. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat2/led.h
  7. 58 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat3/Beat3.ino
  8. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat3/led.h
  9. 30 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink1/Blink1.ino
  10. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink1/led.h
  11. 42 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink2/Blink2.ino
  12. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink2/led.h
  13. 39 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink3/Blink3.ino
  14. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink3/led.h
  15. 44 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink4/Blink4.ino
  16. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink4/led.h
  17. 42 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink5/Blink5.ino
  18. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink5/led.h
  19. 78 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock1/Clock1.ino
  20. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock1/led.h
  21. 88 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock1_Ansi/Clock1_Ansi.ino
  22. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock1_Ansi/led.h
  23. 87 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock2/Clock2.ino
  24. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock2/led.h
  25. 89 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock3/Clock3.ino
  26. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock3/led.h
  27. 89 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock4/Clock4.ino
  28. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock4/led.h
  29. 48 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Count1/Count1.ino
  30. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Count1/led.h
  31. 183 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Wakeup1/Wakeup1.ino
  32. 49 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Wakeup1/led.h
  33. 55 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/keywords.txt
  34. 9 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/library.properties
  35. 514 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/src/jm_Scheduler.cpp
  36. 204 0
      SE/stuff/P5_Automation-library-dev/jm_Scheduler/src/jm_Scheduler.h

+ 165 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/LICENSE

@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.

+ 231 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/README.md

@@ -0,0 +1,231 @@
+
+<img src="http://jean-marc.paratte.ch/wp-content/uploads/2013/01/diduino1_960x96.jpg" class="header-image" alt="jmP" height="96" width="960">
+
+# jm_Scheduler - A Cooperative Scheduler Library for Arduino
+
+```
+2019-01-03: v1.1.0 - Modifying start() which now fails if coroutine already started.
+2018-04-30: v1.0.10 - library.properties adjustement.
+2018-04-29: v1.0.9 - jm_Scheduler is now compatible with EPS32. 5 new Blink examples added.
+2018-04-19: v1.0.8 - yield() function corrected.
+2018-03-27: v1.0.7 - A Cooperative Scheduler Library for Arduino.
+2018-02-08: v1.0.6 - Minor adjustments.
+2017-10-17: v1.0.5 - Minor adjustments.
+2017-05-08: v1.0.4 - Minor adjustments.
+2017-05-08: v1.0.4 - Minor adjustments.
+2017-05-05: v1.0.3 - Adding yield(),sleep(),rearm_async(). Removing void rearm(timestamp_t time, timestamp_t ival);
+2017-04-26: v1.0.2 - Adding void rearm(timestamp_t time, timestamp_t ival);
+2017-03-29: v1.0.1 - Minor adjustments.
+2016-07-08: v1.0.0 - Initial commit.
+```
+
+### Concept
+
+**jm_Scheduler** schedules repeated and intervaled coroutines like the JavaScript `setInterval()` function does,
+but with some improvements:
+
+- By default, **jm_Scheduler** starts immediately the coroutine and repeats it periodically.
+- The first execution can be differed.
+- The repeated executions can be voided.
+- The interval between executions can be dynamically changed.
+- The scheduled coroutine function can be dynamically changed.
+- The scheduled coroutine can be stopped and later restarted.
+
+**jm_Scheduler** doesn't schedule like the official [**Scheduler** Library for Arduino DUE and ZERO](https://www.arduino.cc/en/Reference/Scheduler) does,
+`yield()` function which suspends a task is implemented, but 
+`startLoop()` function which allocates a stack to the new task is not implemented.
+
+**jm_Scheduler** schedules tasks sequentially on the stack processor.
+The rules to _yield_ and _resume_ are:
+
+- _yield_ comes out when coroutine leaves at end of function or by an explicit `return` instruction.
+- _resume_ to a next state can be done with a variable and a `switch` instruction. Or:
+- _resume_ to a next state can be done by switching to another function.
+- Persistent variables must be implemented _global_ or _local_ with the pragma `static`.
+
+
+### Basic Example
+
+	// This example schedules a coroutine every second
+	
+	#include <jm_Scheduler.h>
+  
+	jm_Scheduler scheduler;
+	
+	void coroutine()
+	{
+		Serial.print('.');
+	}
+  
+	void setup(void)
+	{
+		Serial.begin(9600);
+		
+		scheduler.start(coroutine, TIMESTAMP_1SEC); // Start immediately coroutine() and repeat it every second
+	}
+  
+	void loop(void)
+	{
+		yield();
+	}
+
+
+### Study Plan
+
+- NEW 2018-04-29: Begin with the 5 **Blink** progressive examples.
+They demonstrate how to blink a led by replacing delay() Arduino function with rearm() jm_Scheduler method.
+- Begin with example **Clock1.ino**. This example demonstrates the advantage to start immediately a time display coroutine and periodically repeat it.
+- Follow with examples **Clock2.ino** and **Clock3.ino** which present other timing ways.
+- **Clock4.ino** example presents a usefully **jm_Scheduler** technical: changing dynamically the function to execute.
+- **Beat1.ino** and **Beat2.ino** examples present interaction between 2 scheduled coroutines.
+- **Wakeup1.ino** example demonstrates the possible interaction between an interrupt and a scheduled coroutine, implementing a timeout.
+
+
+### Timestamp
+
+The _timestamp_ is read from the Arduino function `micros()`.
+By design, the `micros()` function of Arduino UNO and Leonardo running at 16MHz returns a [us] _timestamp_ with a resolution of [4us].
+
+`micros()` declaration is:
+
+```C
+unsigned long micros();
+```
+
+Look at https://www.arduino.cc/en/Reference/Micros for details.
+
+<!--
+### More about Timestamp
+-->
+
+_timestamp_ is a 32bit [us] counter and overflows about every 70 minutes (precisely 1h+11m+34s+967ms+296us).
+
+<!--
+The periodicity of 70 minutes is sometimes not enough to control slow processes.
+Look next section for answers and tricks.
+-->
+
+
+### Timestamp declaration and constants
+
+```C
+typedef uint32_t timestamp_t;
+
+#define timestamp_read() ((timestamp_t)micros())
+
+#define TIMESTAMP_DEAD (0x01CA0000) // coroutine dead time [30s + 15ms + 488us]
+#define TIMESTAMP_TMAX (0xFE35FFFF) // [1h + 11m + 4s + 951ms + 808us - 1]
+
+#define TIMESTAMP_1US	(1UL)					// [1us]
+#define TIMESTAMP_1MS	(1000*TIMESTAMP_1US)	// [1ms]
+#define TIMESTAMP_1SEC	(1000*TIMESTAMP_1MS)	// [1s]
+#define TIMESTAMP_1MIN	(60*TIMESTAMP_1SEC)		// [1 minute]
+#define TIMESTAMP_1HOUR	(60*TIMESTAMP_1MIN)		// [1 hour]
+```
+
+> `timestamp_t` defines the type of all _timestamp_ values.
+
+> `timestamp_read()` returns the instantaneous _timestamp_.
+This function can also be used by interrupt coroutines to _timestamp_ they data.
+
+> `TIMESTAMP_DEAD` is the maximum allowed execution time of a coroutine to guarantee right scheduling.
+If the coroutine doesn't end before, the scheduler could miss very long scheduling (see next).
+
+> `TIMESTAMP_TMAX` is the maximum allowed scheduling time of a coroutine.
+In practice, don't use _timestamp_ values greater than 1 hour.
+
+### jm_Scheduler methods
+
+```C
+// start coroutine immediately
+void start(voidfuncptr_t func);
+
+// start coroutine immediately and repeat it at fixed interval
+void start(voidfuncptr_t func, timestamp_t ival);
+
+// start coroutine on time and repeat it at fixed interval
+void start(voidfuncptr_t func, timestamp_t time, timestamp_t ival);
+
+// stop coroutine, current or scheduled, remove it from chain
+void stop();
+
+// rearm current coroutine and set or reset interval
+void rearm(timestamp_t ival);
+
+// rearm current coroutine, change coroutine function and set or reset interval
+void rearm(voidfuncptr_t func, timestamp_t ival);
+
+> `start()` initiates a scheduler variable, starts a coroutine function, immediately or on time, with or without repetitions.
+`start()` is invoked once. Next `rearm()` allows changing scheduler values.
+
+> `stop()` cancels further execution of a scheduled coroutine. 
+`stop()` can be invoked from inside coroutine or elsewhere.
+If invoked from inside _coroutine_, `stop()` doesn't exit the function, just cancels further execution.
+
+> `rearm()` changes values of a scheduler variable.
+The new values are evaluated on exit coroutine function.
+The main usage is to change _interval_ or _function_ or both or else cancel further execution.
+```
+
+
+### jm_Scheduler loop
+
+```C
+static void cycle();
+```
+
+> `cycle()` is the cornerstone of the scheduler and must be invoked as often as possible. 
+Note that `cycle()` is a _static_ _method_. 
+The right place is in Arduino `loop()` function.
+Example:
+
+```C
+void loop(void)
+{
+	yield();
+}
+```
+
+> `cycle()` can also be invoked in Arduino `setup()` function. Example:
+
+```C
+void setup(void)
+{
+	// here, some jm_Scheduler variables initialized...
+	
+	Serial.begin(9600);
+	while (!Serial)
+	{
+		// wait for USB Serial ready...
+		
+		yield();
+	}
+	
+	// split long setup()...
+
+	yield();
+	
+	// continue setup()...
+}
+```
+
+> `cycle()` can't be invoked from inside a coroutine function.
+
+
+### Good scheduling practices
+
+- To guarantee a good scheduling of all tasks,
+the execution time of each function must be as short as possible.
+
+- Avoid Arduino `delay()` function, use **jm_Scheduler** `rearm()` method with appropriate arguments to split the coroutine in some serialized functions.
+
+- Use same technical for long calculations.
+
+
+### Changing of Timestamp
+
+Here are some hacks that can be implemented by modifying the file **jm_Scheduler.h**.
+
+- Another source for the _timestamp_ could be the [ms] read from the Arduino function `millis()`. 
+- Gain speed during _timestamp_ comparison by shortening the size to 16bit.
+- Obtain very long periodicity by implementing a 64bit _timestamp_.

+ 42 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat1/Beat1.ino

@@ -0,0 +1,42 @@
+
+#define __PROG__ "Beat1"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler beat_scheduler_led_toggle1;
+jm_Scheduler beat_scheduler_led_toggle2;
+
+void beat_coroutine_led_toggle1()
+{
+	led_toggle();
+}
+
+void beat_coroutine_led_toggle2()
+{
+	led_toggle();
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	beat_scheduler_led_toggle1.start(beat_coroutine_led_toggle1, 10000UL); // 10ms
+	beat_scheduler_led_toggle2.start(beat_coroutine_led_toggle2, 10100UL); // 10.1ms
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat1/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 37 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat2/Beat2.ino

@@ -0,0 +1,37 @@
+
+#define __PROG__ "Beat2"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler beat_scheduler_led_toggle1;
+jm_Scheduler beat_scheduler_led_toggle2;
+
+void beat_coroutine_led_toggle()
+{
+	led_toggle();
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	beat_scheduler_led_toggle1.start(beat_coroutine_led_toggle, 10000UL); // 10ms
+	beat_scheduler_led_toggle2.start(beat_coroutine_led_toggle, 10100UL); // 10.1ms
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat2/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 58 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat3/Beat3.ino

@@ -0,0 +1,58 @@
+
+#define __PROG__ "Beat3"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler beat_scheduler;
+
+bool beat_state = false;
+timestamp_t beat_ival = 0;
+
+void beat_coroutine()
+{
+	if (!beat_state)
+	{
+		beat_state = true;
+
+		led_toggle();
+
+		beat_ival += TIMESTAMP_1MS/10; // +0.1ms
+
+		beat_scheduler.rearm(beat_ival);
+	}
+	else
+	{
+		beat_state = false;
+
+		if (beat_ival < 10*TIMESTAMP_1MS)
+			led_toggle();
+		else
+			beat_ival = 0;
+
+		beat_scheduler.rearm(10*TIMESTAMP_1MS - beat_ival); // 10ms - beat_ival
+	}
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	beat_scheduler.start(beat_coroutine, 10*TIMESTAMP_1MS); // 10ms
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Beat3/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 30 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink1/Blink1.ino

@@ -0,0 +1,30 @@
+
+#define __PROG__ "Blink1"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+}
+
+void loop()
+{
+	led_on();
+
+	jm_Scheduler::delay(100);
+
+	led_off();
+
+	jm_Scheduler::delay(900);
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink1/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 42 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink2/Blink2.ino

@@ -0,0 +1,42 @@
+
+#define __PROG__ "Blink2"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler blink_scheduler;
+
+void blink_coroutine()
+{
+	for(;;)
+	{
+		led_on();
+
+		jm_Scheduler::delay(100);
+
+		led_off();
+
+		jm_Scheduler::delay(900);
+	}
+}
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	blink_scheduler.start(blink_coroutine);
+}
+
+void loop()
+{
+	jm_Scheduler::yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink2/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 39 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink3/Blink3.ino

@@ -0,0 +1,39 @@
+
+#define __PROG__ "Blink3"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler blink_scheduler;
+
+void blink_coroutine()
+{
+	led_on();
+
+	jm_Scheduler::delay(100);
+
+	led_off();
+
+	blink_scheduler.rearm(TIMESTAMP_1SEC);
+}
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	blink_scheduler.start(blink_coroutine);
+}
+
+void loop()
+{
+	jm_Scheduler::yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink3/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 44 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink4/Blink4.ino

@@ -0,0 +1,44 @@
+
+#define __PROG__ "Blink4"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler blink_scheduler;
+
+void blink_coroutine()
+{
+	if (!led_state())
+	{
+		led_on();
+
+		blink_scheduler.rearm(100*TIMESTAMP_1MS);
+	}
+	else
+	{
+		led_off();
+
+		blink_scheduler.rearm(900*TIMESTAMP_1MS);
+	}
+}
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	blink_scheduler.start(blink_coroutine);
+}
+
+void loop()
+{
+	jm_Scheduler::yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink4/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 42 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink5/Blink5.ino

@@ -0,0 +1,42 @@
+
+#define __PROG__ "Blink5"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler blink_scheduler;
+
+void blink_on_coroutine()
+{
+	led_on();
+
+	blink_scheduler.rearm(blink_off_coroutine, 100*TIMESTAMP_1MS);
+}
+
+void blink_off_coroutine()
+{
+	led_off();
+
+	blink_scheduler.rearm(blink_on_coroutine, 900*TIMESTAMP_1MS);
+}
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	blink_scheduler.start(blink_on_coroutine);
+}
+
+void loop()
+{
+	jm_Scheduler::yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Blink5/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 78 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock1/Clock1.ino

@@ -0,0 +1,78 @@
+
+#define __PROG__ "Clock1"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+uint8_t clock_sec = 0; // 0..59 seconds => 1 minute
+uint8_t clock_min = 0; // 0..59 minutes => 1 hour
+uint8_t clock_h24 = 0; // 0..23 hours => 1 day
+
+void clock_inc()
+{
+	clock_sec++;
+	if (clock_sec == 60)
+	{
+		clock_sec = 0;
+		clock_min++;
+		if (clock_min == 60)
+		{
+			clock_min = 0;
+			clock_h24++;
+			if (clock_h24 == 24) clock_h24 = 0;
+		}
+	}
+}
+
+void clock_display()
+{
+	Serial.print( clock_h24/10 );
+	Serial.print( clock_h24%10 );
+	Serial.print( ':' );
+	Serial.print( clock_min/10 );
+	Serial.print( clock_min%10 );
+	Serial.print( ':' );
+	Serial.print( clock_sec/10 );
+	Serial.print( clock_sec%10 );
+	Serial.println();
+}
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler clock_scheduler;
+
+void clock_coroutine()
+{
+	static bool coroutine_first_start = true;
+
+	if (!coroutine_first_start) clock_inc();
+
+	led_write(!(clock_sec & 1));
+
+	clock_display();
+
+	coroutine_first_start = false;
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	clock_scheduler.start(clock_coroutine, TIMESTAMP_1SEC); // Start coroutine immediately and repeat it every 1s.
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock1/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 88 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock1_Ansi/Clock1_Ansi.ino

@@ -0,0 +1,88 @@
+
+#define __PROG__ "Clock1_Ansi"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+uint8_t clock_sec = 0; // 0..59 seconds => 1 minute
+uint8_t clock_min = 0; // 0..59 minutes => 1 hour
+uint8_t clock_h24 = 0; // 0..23 hours => 1 day
+
+void clock_inc()
+{
+	clock_sec++;
+	if (clock_sec == 60)
+	{
+		clock_sec = 0;
+		clock_min++;
+		if (clock_min == 60)
+		{
+			clock_min = 0;
+			clock_h24++;
+			if (clock_h24 == 24) clock_h24 = 0;
+		}
+	}
+}
+
+void clock_display()
+{
+	Serial.print( F("\x1B[s") );		// Save Cursor Position
+	Serial.print( F("\x1B[1;71H") );	// Set Cursor Position
+
+	Serial.print( clock_h24/10 );
+	Serial.print( clock_h24%10 );
+	Serial.print( ':' );
+	Serial.print( clock_min/10 );
+	Serial.print( clock_min%10 );
+	Serial.print( ':' );
+	Serial.print( clock_sec/10 );
+	Serial.print( clock_sec%10 );
+//	Serial.println();
+
+	Serial.print( F("\x1B[u") );		// Restore Cursor Position
+}
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler clock_scheduler;
+
+void clock_coroutine()
+{
+	static bool coroutine_first_start = true;
+
+	if (!coroutine_first_start) clock_inc();
+
+	led_write(!(clock_sec & 1));
+
+	clock_display();
+
+	coroutine_first_start = false;
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+
+	Serial.print( F("\x1B[H") );	// Cursor home
+	Serial.print( F("\x1B[2J") );	// Clear Screen
+
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	clock_scheduler.start(clock_coroutine, TIMESTAMP_1SEC); // Start coroutine immediately and repeat it every 1s.
+}
+
+void loop()
+{
+	yield();
+}
+

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock1_Ansi/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 87 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock2/Clock2.ino

@@ -0,0 +1,87 @@
+
+#define __PROG__ "Clock2"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+uint8_t clock_t50 = 0; // 0..49 ticks(20ms/50hz) => 1 second
+
+uint8_t clock_sec = 0; // 0..59 seconds => 1 minute
+uint8_t clock_min = 0; // 0..59 minutes => 1 hour
+uint8_t clock_h24 = 0; // 0..23 hours => 1 day
+
+void clock_inc()
+{
+	clock_sec++;
+	if (clock_sec == 60)
+	{
+		clock_sec = 0;
+		clock_min++;
+		if (clock_min == 60)
+		{
+			clock_min = 0;
+			clock_h24++;
+			if (clock_h24 == 24) clock_h24 = 0;
+		}
+	}
+}
+
+void clock_display()
+{
+	Serial.print( clock_h24/10 );
+	Serial.print( clock_h24%10 );
+	Serial.print( ':' );
+	Serial.print( clock_min/10 );
+	Serial.print( clock_min%10 );
+	Serial.print( ':' );
+	Serial.print( clock_sec/10 );
+	Serial.print( clock_sec%10 );
+	Serial.println();
+}
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler clock_scheduler;
+
+void clock_coroutine()
+{
+	if (clock_t50 == 0) led_on(); // LED ON, pulse 20ms every 1s
+	if (clock_t50 == 1) led_off(); // LED OFF.
+
+	if (clock_t50 == 0) // display clock every second
+	{
+		clock_display();
+	}
+
+	clock_t50++;
+
+	if (clock_t50 == 50)
+	{
+		clock_t50 = 0;
+
+		clock_inc();
+	}
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	clock_scheduler.start(clock_coroutine, 20*TIMESTAMP_1MS); // Start coroutine immediately and repeat it every 20ms => 50hz.
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock2/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 89 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock3/Clock3.ino

@@ -0,0 +1,89 @@
+
+#define __PROG__ "Clock3"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+uint8_t clock_sec = 0; // 0..59 seconds => 1 minute
+uint8_t clock_min = 0; // 0..59 minutes => 1 hour
+uint8_t clock_h24 = 0; // 0..23 hours => 1 day
+
+void clock_inc()
+{
+	clock_sec++;
+	if (clock_sec == 60)
+	{
+		clock_sec = 0;
+		clock_min++;
+		if (clock_min == 60)
+		{
+			clock_min = 0;
+			clock_h24++;
+			if (clock_h24 == 24) clock_h24 = 0;
+		}
+	}
+}
+
+void clock_display()
+{
+	Serial.print( clock_h24/10 );
+	Serial.print( clock_h24%10 );
+	Serial.print( ':' );
+	Serial.print( clock_min/10 );
+	Serial.print( clock_min%10 );
+	Serial.print( ':' );
+	Serial.print( clock_sec/10 );
+	Serial.print( clock_sec%10 );
+	Serial.println();
+}
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler clock_scheduler;
+
+void clock_coroutine()
+{
+	static bool coroutine_first_start = true;
+
+	if (!led_state())
+	{
+		if (!coroutine_first_start) clock_inc();
+
+		led_on(); // LED ON, pulse LED every second
+
+		clock_display();
+
+		clock_scheduler.rearm( 20*TIMESTAMP_1MS ); // 20ms
+	}
+	else
+	{
+		led_off(); // LED OFF
+
+		clock_scheduler.rearm( TIMESTAMP_1SEC - 20*TIMESTAMP_1MS ); // 1s - 20ms
+	}
+
+	coroutine_first_start = false;
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	clock_scheduler.start(clock_coroutine); // Start coroutine immediately, interval will be set later.
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock3/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 89 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock4/Clock4.ino

@@ -0,0 +1,89 @@
+
+#define __PROG__ "Clock4"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+uint8_t clock_sec = 0; // 0..59 seconds => 1 minute
+uint8_t clock_min = 0; // 0..59 minutes => 1 hour
+uint8_t clock_h24 = 0; // 0..23 hours => 1 day
+
+void clock_inc()
+{
+	clock_sec++;
+	if (clock_sec == 60)
+	{
+		clock_sec = 0;
+		clock_min++;
+		if (clock_min == 60)
+		{
+			clock_min = 0;
+			clock_h24++;
+			if (clock_h24 == 24) clock_h24 = 0;
+		}
+	}
+}
+
+void clock_display()
+{
+	Serial.print( clock_h24/10 );
+	Serial.print( clock_h24%10 );
+	Serial.print( ':' );
+	Serial.print( clock_min/10 );
+	Serial.print( clock_min%10 );
+	Serial.print( ':' );
+	Serial.print( clock_sec/10 );
+	Serial.print( clock_sec%10 );
+	Serial.println();
+}
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler clock_scheduler;
+
+void clock_coroutine_led_off();
+
+void clock_coroutine_led_on()
+{
+	static bool coroutine_first_start = true;
+
+	if (!coroutine_first_start) clock_inc();
+
+	led_on(); // LED ON, pulse LED every second
+
+	clock_display();
+
+	coroutine_first_start = false;
+
+	clock_scheduler.rearm( clock_coroutine_led_off, 20*TIMESTAMP_1MS ); // 20ms
+}
+
+void clock_coroutine_led_off()
+{
+	led_off(); // LED OFF
+
+	clock_scheduler.rearm( clock_coroutine_led_on, TIMESTAMP_1SEC - 20*TIMESTAMP_1MS ); // 1s - 20ms
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	clock_scheduler.start(clock_coroutine_led_on); // Start coroutine immediately, interval will be set later.
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Clock4/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 48 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Count1/Count1.ino

@@ -0,0 +1,48 @@
+
+#define __PROG__ "Count1"
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+long count = 0;
+
+jm_Scheduler count1_scheduler;
+
+void count1_coroutine()
+{
+	led_toggle();
+	count++;
+	count1_scheduler.rearm_async(1);
+}
+
+jm_Scheduler count_scheduler;
+
+void count_coroutine()
+{
+	Serial.println(count);
+	count = 0;
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	count1_scheduler.start(count1_coroutine); // Start coroutine immediately.
+	count_scheduler.start(count_coroutine, TIMESTAMP_1SEC); // Start coroutine immediately and repeat it every 1s.
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Count1/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 183 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Wakeup1/Wakeup1.ino

@@ -0,0 +1,183 @@
+
+#define __PROG__ "Wakeup1"
+
+/*
+	Wakeup1.ino demonstrate the possible interaction of interrupt with scheduled coroutine.
+
+	Wakeup1.ino implements an 10s timeout to receive an interrupt.
+	The interrupt is activated when the Arduino UNO pin 2 is shortcut to GND.
+	The elapsed time between Arduino RESET and pin INT is printed.
+	If no interrupt is provided during 10s, then the message "timeout" is printed.
+
+	Copyright (c) 2016,2015 Jean-Marc Paratte
+
+	Wakeup1.ino is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Wakeup1.ino is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Wakeup1.ino.  If not, see <http://www.gnu.org/licenses/>.
+
+    Last revised: 2016-07-08,2015-06-29
+*/
+
+#include <jm_Scheduler.h>
+
+#include "led.h"
+
+//------------------------------------------------------------------------------
+
+/*
+	https://www.arduino.cc/en/Reference/AttachInterrupt.html
+
+	Board								Digital Pins Usable For Interrupts
+	----------------------------------------------------------------------
+	Uno, Nano, Mini, other 328-based	2, 3
+	Mega, Mega2560, MegaADK				2, 3, 18, 19, 20, 21
+	Micro, Leonardo, other 32u4-based	0, 1, 2, 3, 7
+	Zero								all digital pins, except 4
+	MKR1000 Rev.1						0, 1, 4, 5, 6, 7, 8, 9, A1, A2
+	Due									all digital pins
+*/
+
+#define WAKEUP_PIN (2) // All models same digital pin usable for interrupts except MKR1000 Rev.1
+
+//------------------------------------------------------------------------------
+
+const timestamp_t WAKEUP_TIMEOUT = 5*TIMESTAMP_1SEC; // 5s
+
+jm_Scheduler wakeup_scheduler;
+
+void wakeup_coroutine_start()
+{
+	Serial.print(F("          "));
+	Serial.println( F("start... ") );
+
+	led_on(); // LED ON
+
+	wakeup_scheduler.rearm( wakeup_coroutine_stop, WAKEUP_TIMEOUT ); // set timeout
+
+	// flush possible pending FALLING interrupt
+	attachInterrupt(digitalPinToInterrupt(WAKEUP_PIN), dummy_interrupt, FALLING); // attach int.0 (Arduino UNO pin 2).
+//	detachInterrupt(digitalPinToInterrupt(WAKEUP_PIN)); // detach int.0 (Arduino UNO pin 2).
+
+	attachInterrupt(digitalPinToInterrupt(WAKEUP_PIN), wakeup_interrupt, FALLING); // attach int.0 (Arduino UNO pin 2).
+}
+
+void wakeup_coroutine_stop()
+{
+	detachInterrupt(digitalPinToInterrupt(WAKEUP_PIN)); // detach int.0 (Arduino UNO pin 2).
+
+	led_off(); // LED OFF
+
+	timestamp_t wakeup_time = wakeup_scheduler.wakeup_time;
+	timestamp_t wakeup_count = wakeup_scheduler.wakeup_read();
+
+	if (wakeup_count == 0) // timeout ?
+	{
+		Serial.print(F("          "));
+		Serial.println( F("timeout") );
+	}
+	else
+	{
+		Serial.print(F("          "));
+		Serial.print( (wakeup_time - (wakeup_scheduler.time - WAKEUP_TIMEOUT))/1E6, 6 ); // print elapsed time in seconds.
+		Serial.println( F("s") );
+		Serial.print(F("          "));
+		Serial.print( wakeup_count );
+		Serial.println( F(" wakeup(s)") ); // print count of wakeups
+	}
+
+	wakeup_scheduler.stop(); // stop coroutine
+}
+
+void wakeup_interrupt()
+{
+	wakeup_scheduler.wakeup();
+}
+
+void dummy_interrupt()
+{
+	// does nothing!
+}
+
+//------------------------------------------------------------------------------
+
+uint8_t clock_sec = 0; // 0..59 seconds => 1 minute
+uint8_t clock_min = 0; // 0..59 minutes => 1 hour
+uint8_t clock_h24 = 0; // 0..23 hours => 1 day
+
+void clock_inc()
+{
+	clock_sec++;
+	if (clock_sec == 60)
+	{
+		clock_sec = 0;
+		clock_min++;
+		if (clock_min == 60)
+		{
+			clock_min = 0;
+			clock_h24++;
+			if (clock_h24 == 24) clock_h24 = 0;
+		}
+	}
+}
+
+void clock_display()
+{
+	Serial.print( clock_h24/10 );
+	Serial.print( clock_h24%10 );
+	Serial.print( ':' );
+	Serial.print( clock_min/10 );
+	Serial.print( clock_min%10 );
+	Serial.print( ':' );
+	Serial.print( clock_sec/10 );
+	Serial.print( clock_sec%10 );
+	Serial.println();
+}
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler clock_scheduler;
+
+void clock_coroutine()
+{
+	static bool coroutine_first_start = true;
+
+	if (!coroutine_first_start) clock_inc();
+
+	clock_display();
+
+	if (!wakeup_scheduler && digitalRead(WAKEUP_PIN)) wakeup_scheduler.start(wakeup_coroutine_start);
+
+	coroutine_first_start = false;
+}
+
+//------------------------------------------------------------------------------
+
+void setup()
+{
+	Serial.begin(115200);
+	while (!Serial && millis()<3000); // timeout 3s for USB Serial ready
+	Serial.print(F(__PROG__));
+	Serial.print(F("..."));
+	Serial.println();
+
+	led_init();
+
+	clock_scheduler.start(clock_coroutine, TIMESTAMP_1SEC); // Start coroutine immediately and repeat it every 1s.
+
+	pinMode(WAKEUP_PIN, INPUT_PULLUP); // Arduino UNO pin 2 is int.0
+//	while (!digitalRead(WAKEUP_PIN)); // wait for pullup
+}
+
+void loop()
+{
+	yield();
+}

+ 49 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/examples/Wakeup1/led.h

@@ -0,0 +1,49 @@
+
+#ifdef ARDUINO_ARCH_ESP32
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2
+#warning LED_BUILTIN has been defined hopefully on digital pin 2 in this file.
+#endif
+#define LED_ON LOW
+#define LED_OFF HIGH
+#else
+#define LED_ON HIGH
+#define LED_OFF LOW
+#endif
+
+#ifndef LED_BUILTIN
+#error LED_BUILTIN is undefined! Please define one in this file.
+#endif
+
+// C:\Arduino15\hardware\arduino\avr\cores\arduino
+
+void led_init()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+	pinMode(LED_BUILTIN, OUTPUT);
+}
+
+bool led_state()
+{
+	return (digitalRead(LED_BUILTIN) == LED_ON);
+}
+
+void led_on()
+{
+	digitalWrite(LED_BUILTIN, LED_ON);
+}
+
+void led_off()
+{
+	digitalWrite(LED_BUILTIN, LED_OFF);
+}
+
+void led_write(bool state)
+{
+	if (state) led_on(); else led_off();
+}
+
+void led_toggle()
+{
+	led_write(!led_state());
+}

+ 55 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/keywords.txt

@@ -0,0 +1,55 @@
+#######################################
+# Syntax Coloring Map for jm_Scheduler Library
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+jm_Scheduler	KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+voidfuncptr_t	KEYWORD2
+vfp_vpu32b_t	KEYWORD2
+timestamp_t	KEYWORD2
+timestamp_read	KEYWORD2
+
+jm_Scheduler_time_read	KEYWORD2
+jm_Scheduler_tref_read	KEYWORD2
+jm_Scheduler_tref_ival	KEYWORD2
+
+jm_Scheduler_time_ge_time	KEYWORD2
+jm_Scheduler_tref_ge_time	KEYWORD2
+jm_Scheduler_tref_ival_ge_time	KEYWORD2
+
+display	KEYWORD2
+
+time_cycle	KEYWORD2
+cycle	KEYWORD2
+yield	KEYWORD2
+
+delay	KEYWORD2
+delayMicroseconds	KEYWORD2
+
+start	KEYWORD2
+stop	KEYWORD2
+rearm	KEYWORD2
+rearm_async	KEYWORD2
+wakeup	KEYWORD2
+wakeup_read	KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+
+TIMESTAMP_DEAD	LITERAL1
+TIMESTAMP_TMAX	LITERAL1
+
+TIMESTAMP_1US	LITERAL1
+TIMESTAMP_1MS	LITERAL1
+TIMESTAMP_1SEC	LITERAL1
+TIMESTAMP_1MIN	LITERAL1
+TIMESTAMP_1HOUR	LITERAL1

+ 9 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/library.properties

@@ -0,0 +1,9 @@
+name=jm_Scheduler
+version=1.1.0
+author=Jean-Marc Paratte <jean-marc@paratte.ch>
+maintainer=Jean-Marc Paratte <jean-marc@paratte.ch>
+sentence=A Cooperative Scheduler Library for Arduino.
+paragraph=Schedules coroutines, starts, stops, restarts and wakeups them. Timestamp is read from micros() function.
+category=Timing
+url=https://github.com/jmparatte/jm_Scheduler
+architectures=*

+ 514 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/src/jm_Scheduler.cpp

@@ -0,0 +1,514 @@
+/*
+	jm_Scheduler
+	============
+
+	jm_Scheduler.h and jm_Scheduler.cpp - Implementation of a general
+	cooperative scheduler named "jm_Scheduler" to use in various environment
+	like Arduino, Energia, MBED, etc...
+
+	Copyright (c) 2019,2018,2017,2016,2015 Jean-Marc Paratte
+
+	jm_Scheduler is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Less General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    jm_Scheduler is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+    GNU Less General Public License for more details.
+
+    You should have received a copy of the GNU Less General Public License
+    along with jm_Scheduler. If not, see <http://www.gnu.org/licenses/>.
+
+    Last revised: 2019-01-03,2018-03-27,2018-02-08,2017-11-10,2017-07-20,2017-04-26,2016-07-07,2016-04-27,2015-06-29
+*/
+
+#include <jm_Scheduler.h>
+
+#include <Arduino.h> // micros(),...
+
+//------------------------------------------------------------------------------
+
+timestamp_t jm_Scheduler::tref = timestamp_read();	// current scheduler time
+jm_Scheduler *jm_Scheduler::first = NULL;			// first scheduled coroutine chain
+jm_Scheduler *jm_Scheduler::crnt = NULL;			// current running coroutine
+
+jm_Scheduler *jm_Scheduler::wakeup_first = NULL;	// first wakeup coroutine chain
+
+void jm_Scheduler::chain_insert()
+{
+	jm_Scheduler *prev1 = NULL;
+	jm_Scheduler *next1 = jm_Scheduler::first;
+
+	while (next1 && jm_Scheduler_time_ge_time(this->time, next1->time))
+	{
+		prev1 = next1;
+		next1 = next1->next;
+	}
+
+	if (prev1) prev1->next = this; else jm_Scheduler::first = this;
+
+	this->next = next1;
+}
+
+void jm_Scheduler::chain_remove()
+{
+	jm_Scheduler *prev1 = NULL;
+	jm_Scheduler *next1 = jm_Scheduler::first;
+
+	while (next1)
+	{
+		if (next1 == this) break;
+
+		prev1 = next1;
+		next1 = next1->next;
+	}
+
+	if (next1)
+	{
+		if (prev1)
+			prev1->next = this->next;
+		else
+			jm_Scheduler::first = this->next;
+	}
+
+	this->next = NULL;
+}
+
+void jm_Scheduler::wakeup_chain_append()
+{
+	jm_Scheduler *wakeup_prev1 = NULL;
+	jm_Scheduler *wakeup_next1 = jm_Scheduler::wakeup_first;
+
+	while (wakeup_next1) // loop wakeup_chain
+	{
+		if (wakeup_next1 == this) return; // already inserted in wakeup_chain ? exit function
+
+		wakeup_prev1 = wakeup_next1;
+		wakeup_next1 = wakeup_next1->wakeup_next;
+	}
+	// end of wakeup_chain reached, this not found in it
+
+	// insert this at end of wakeup_chain
+	if (wakeup_prev1)
+		wakeup_prev1->wakeup_next = this;
+	else
+		jm_Scheduler::wakeup_first = this;
+}
+
+void jm_Scheduler::wakeup_chain_remove()
+{
+	jm_Scheduler *wakeup_prev1 = NULL;
+	jm_Scheduler *wakeup_next1 = jm_Scheduler::wakeup_first;
+
+	while (wakeup_next1) // loop wakeup_chain
+	{
+		if (wakeup_next1 == this) // this found in wakeup_chain ?
+		{
+			// remove from wakeup_chain
+			if (wakeup_prev1)
+				wakeup_prev1->wakeup_next = this->wakeup_next;
+			else
+				jm_Scheduler::wakeup_first = this->wakeup_next;
+			this->wakeup_next = NULL;
+
+			return; // now removed from wakeup_chain, exit function
+		}
+
+		wakeup_prev1 = wakeup_next1;
+		wakeup_next1 = wakeup_next1->wakeup_next;
+	}
+}
+
+//------------------------------------------------------------------------------
+
+jm_Scheduler::jm_Scheduler() :
+	func(NULL),
+	time(0),
+	ival(0),
+
+	next(NULL),
+
+	wakeup_time(0),				// time of first wakeup coroutine chain
+	wakeup_next(NULL),			// next in wakeup coroutine chain
+	wakeup_count(0),			// count of repeated interrupt coroutine
+
+	started(false),
+	stopping(false),
+	yielded(false)
+{
+}
+
+jm_Scheduler::~jm_Scheduler()
+{
+	this->stop();
+}
+
+jm_Scheduler::operator bool()
+{
+	return (this->started);
+}
+
+//------------------------------------------------------------------------------
+
+void jm_Scheduler::display(int line)
+{
+	Serial.print(line);
+	Serial.print(':');
+	Serial.print(jm_Scheduler::tref);
+
+	Serial.print(F(" first="));
+	Serial.print((long)jm_Scheduler::first);
+
+	Serial.print(F(" crnt="));
+	Serial.print((long)jm_Scheduler::crnt);
+
+	Serial.print(F(" this="));
+	Serial.print((long)this);
+
+	Serial.print(F(" time="));
+	Serial.print(this->time);
+
+	Serial.print(F(" ival="));
+	Serial.print(this->ival);
+
+	Serial.print(F(" next="));
+	Serial.print((long)this->next);
+
+	Serial.println();
+	Serial.flush();
+}
+
+//------------------------------------------------------------------------------
+
+void jm_Scheduler::time_cycle()
+{
+	jm_Scheduler::tref = timestamp_read();
+}
+
+void jm_Scheduler::cycle()
+{
+	for (;;)
+{
+	jm_Scheduler::time_cycle();
+
+	noInterrupts();
+
+	if (jm_Scheduler::wakeup_first)
+	{
+		jm_Scheduler *wakeup_first0 = jm_Scheduler::wakeup_first;
+
+		// remove wakeup_first
+		jm_Scheduler::wakeup_first = wakeup_first0->wakeup_next;
+		wakeup_first0->wakeup_next = NULL;
+
+		// remove wakeuped coroutine from coroutine chain
+		wakeup_first0->chain_remove();
+
+		// insert wakeuped coroutine at first coroutine
+		wakeup_first0->next = jm_Scheduler::first;
+		jm_Scheduler::first = wakeup_first0;
+
+		interrupts();
+	}
+	else
+	{
+		interrupts();
+
+		if (jm_Scheduler::first == NULL) break;
+
+		if (!jm_Scheduler_tref_ge_time(jm_Scheduler::first->time)) break;
+	}
+
+	// set crnt with first
+	jm_Scheduler::crnt = jm_Scheduler::first;
+
+	// remove first from chain coroutine
+	jm_Scheduler::first = jm_Scheduler::crnt->next;
+	jm_Scheduler::crnt->next = NULL;
+
+	jm_Scheduler::crnt->func(); // call coroutine function
+
+	if (jm_Scheduler::crnt->stopping || jm_Scheduler::crnt->ival == 0) // stopping or not rearmed ?
+	{
+		jm_Scheduler::crnt->started = false;
+		jm_Scheduler::crnt->stopping = false;
+
+		jm_Scheduler::crnt->wakeup_chain_remove();
+	}
+	else // rearmed/intervalled calls
+	{
+		jm_Scheduler::crnt->time += jm_Scheduler::crnt->ival; // synchonous
+
+		jm_Scheduler::crnt->chain_insert();
+	}
+
+	jm_Scheduler::crnt = NULL;
+}
+
+//#ifdef ARDUINO_ARCH_ESP32
+#ifdef FREERTOS_USED
+	yield();
+#endif
+}
+
+void jm_Scheduler::yield()
+{
+	if (jm_Scheduler::crnt) // called from a running coroutine ?
+	{
+		// backup coroutine states
+//		timestamp_t tref0 = jm_Scheduler::tref;
+		jm_Scheduler *crnt0 = jm_Scheduler::crnt;
+
+		// set coroutine yielded state
+		crnt0->yielded = true;
+
+		jm_Scheduler::crnt = NULL; // free scheduler from current coroutine
+		jm_Scheduler::cycle(); // yield current coroutine
+
+		// clr coroutine yielded state
+		crnt0->yielded = false;
+
+		// restore coroutine states
+		jm_Scheduler::crnt = crnt0;
+//		jm_Scheduler::tref = tref0;
+	}
+	else // called from setup() or loop().
+	{
+		jm_Scheduler::cycle();
+	}
+}
+
+//void jm_Scheduler::sleep(timestamp_t ival)
+//{
+//	timestamp_t time1 = jm_Scheduler_time_read() + ival;
+//	while (!jm_Scheduler_time_ge_time(jm_Scheduler_time_read(), time1)) jm_Scheduler::yield();
+//}
+
+//------------------------------------------------------------------------------
+
+void jm_Scheduler::delay(unsigned long ms)
+{
+	timestamp_t time1 = jm_Scheduler_time_read() + ms*1000;
+	while (!jm_Scheduler_time_ge_time(jm_Scheduler_time_read(), time1)) jm_Scheduler::yield();
+}
+
+void jm_Scheduler::delayMicroseconds(unsigned int us)
+{
+	timestamp_t time1 = jm_Scheduler_time_read() + us;
+	while (!jm_Scheduler_time_ge_time(jm_Scheduler_time_read(), time1)) jm_Scheduler::yield();
+}
+
+//------------------------------------------------------------------------------
+
+// start coroutine immediately
+bool jm_Scheduler::start(voidfuncptr_t func) // OK
+{
+	if (this->started) return false; // already started ?
+
+	this->func = func;
+	this->time = jm_Scheduler_time_read();
+	this->ival = 0;
+
+	this->chain_insert();
+
+	this->wakeup_time = 0;		// time of first wakeup (may be repeated)
+	this->wakeup_next = NULL;	// next coroutine in wakeup coroutine chain
+	this->wakeup_count = 0;		// count of repeated wakeup
+
+	this->started = true;
+	this->stopping = false;
+	this->yielded = false;
+
+	return true; // started
+}
+
+// start coroutine immediately and repeat it at fixed intervals
+bool jm_Scheduler::start(voidfuncptr_t func, timestamp_t ival) // OK
+{
+	if (this->started) return false; // already started ?
+
+	this->func = func;
+	this->time = jm_Scheduler_time_read();
+	this->ival = ival;
+
+	this->chain_insert();
+
+	this->wakeup_time = 0;		// time of first wakeup (may be repeated)
+	this->wakeup_next = NULL;	// next coroutine in wakeup coroutine chain
+	this->wakeup_count = 0;		// count of repeated wakeup
+
+	this->started = true;
+	this->stopping = false;
+	this->yielded = false;
+
+	return true; // started
+}
+
+// start coroutine on time and repeat it at fixed intervals
+bool jm_Scheduler::start(voidfuncptr_t func, timestamp_t time, timestamp_t ival) // OK
+{
+	if (this->started) return false; // already started ?
+
+	this->func = func;
+	this->time = time;
+	this->ival = ival;
+
+	this->chain_insert();
+
+	this->wakeup_time = 0;		// time of first wakeup (may be repeated)
+	this->wakeup_next = NULL;	// next coroutine in wakeup coroutine chain
+	this->wakeup_count = 0;		// count of repeated wakeup
+
+	this->started = true;
+	this->stopping = false;
+	this->yielded = false;
+
+	return true; // started
+}
+
+// stop coroutine, current or scheduled, remove from chain
+void jm_Scheduler::stop()
+{
+	if (!this->started || this->stopping) return;
+
+	if (this == jm_Scheduler::crnt) // coroutine running ?
+	{
+		this->stopping = true;
+	}
+	else
+	{
+		this->started = false;
+		this->stopping = false;
+		this->yielded = false;
+
+		this->chain_remove();
+	}
+}
+
+//------------------------------------------------------------------------------
+
+// rearm coroutine
+void jm_Scheduler::rearm()
+{
+}
+
+// rearm coroutine asynchronously
+void jm_Scheduler::rearm_async()
+{
+	this->time = jm_Scheduler_time_read();
+}
+
+// rearm coroutine and set next interval
+void jm_Scheduler::rearm(timestamp_t ival)
+{
+	this->ival = ival;
+}
+
+// rearm coroutine asynchronously and set next interval
+void jm_Scheduler::rearm_async(timestamp_t ival)
+{
+	this->time = jm_Scheduler_time_read();
+	this->ival = ival;
+}
+
+//// rearm coroutine, set time and set next interval
+//void jm_Scheduler::rearm(timestamp_t time, timestamp_t ival)
+//{
+//	this->time = time;
+//	this->ival = ival;
+//}
+
+// rearm coroutine, change coroutine function and set next interval
+void jm_Scheduler::rearm(voidfuncptr_t func, timestamp_t ival)
+{
+	this->func = func;
+	this->ival = ival;
+}
+
+// rearm coroutine asynchronously, change coroutine function and set next interval
+void jm_Scheduler::rearm_async(voidfuncptr_t func, timestamp_t ival)
+{
+	this->time = jm_Scheduler_time_read();
+	this->func = func;
+	this->ival = ival;
+}
+
+//// rearm coroutine, change coroutine function, set time and set next interval
+//void jm_Scheduler::rearm(voidfuncptr_t func, timestamp_t time, timestamp_t ival)
+//{
+//	this->func = func;
+//	this->time = time;
+//	this->ival = ival;
+//}
+
+//------------------------------------------------------------------------------
+
+// wakeup a scheduled coroutine (maybe repeated)
+void jm_Scheduler::wakeup()
+{
+	if (!this->started) return;
+
+//	if (this == jm_Scheduler::crnt) return;
+
+	if (this->wakeup_count == 0) // set wakeup_time if never set before
+	{
+		this->wakeup_time = timestamp_read();
+
+		this->wakeup_chain_append();
+	}
+
+	this->wakeup_count++; // inc wakeup_count
+}
+
+// wakeup a scheduled coroutine (maybe repeated but only 1st wakeup_time is recorded)
+void jm_Scheduler::wakeup(uint32_t wakeup_time)
+{
+	if (!this->started) return;
+
+//	if (this == jm_Scheduler::crnt) return;
+
+	if (this->wakeup_count == 0) // set wakeup_time if never set before
+	{
+		this->wakeup_time = wakeup_time;
+
+		this->wakeup_chain_append();
+	}
+
+	this->wakeup_count++; // inc wakeup_count
+}
+
+// read wake_count, reset it and remove coroutine from wakeup chain
+int jm_Scheduler::wakeup_read()
+{
+	int count = 0;
+
+	noInterrupts();
+
+	if (this->wakeup_count)
+	{
+		count = this->wakeup_count;
+		this->wakeup_count = 0;
+
+		this->wakeup_chain_remove();
+	}
+
+	interrupts();
+
+	return count;
+}
+
+//------------------------------------------------------------------------------
+
+#ifdef ARDUINO_ARCH_ESP32
+#else
+void yield(void)
+{
+	jm_Scheduler::yield();
+}
+#endif
+
+//------------------------------------------------------------------------------
+
+// END.

+ 204 - 0
SE/stuff/P5_Automation-library-dev/jm_Scheduler/src/jm_Scheduler.h

@@ -0,0 +1,204 @@
+/*
+	jm_Scheduler
+	============
+
+	jm_Scheduler.h and jm_Scheduler.cpp - Implementation of a general
+	cooperative scheduler named "jm_Scheduler" to use in various environment
+	like Arduino, Energia, MBED, etc...
+
+	Copyright (c) 2019,2018,2017,2016,2015 Jean-Marc Paratte
+
+	jm_Scheduler is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Less General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    jm_Scheduler is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+    GNU Less General Public License for more details.
+
+    You should have received a copy of the GNU Less General Public License
+    along with jm_Scheduler. If not, see <http://www.gnu.org/licenses/>.
+
+    Last revised: 2019-01-03,2018-03-27,2018-02-08,2017-11-10,2017-07-20,2017-04-26,2016-07-07,2016-04-27,2015-06-29
+*/
+
+#ifndef jm_Scheduler_h
+#define jm_Scheduler_h
+
+//------------------------------------------------------------------------------
+
+//#include <Arduino.h>
+#include <stddef.h>
+#include <stdint.h>
+
+//----------------------------------------------------------------------
+
+#ifndef voidfuncptr_t
+#define voidfuncptr_t voidfuncptr_t
+typedef void (*voidfuncptr_t)(void); // void function pointer typedef
+#endif
+
+#ifndef vfp_vpu32b_t
+#define vfp_vpu32b_t vfp_vpu32b_t
+typedef void (*vfp_vpu32b_t)(void*, uint32_t, bool);
+#endif
+
+//----------------------------------------------------------------------
+
+#ifndef timestamp_t
+#define timestamp_t timestamp_t
+typedef uint32_t timestamp_t;
+#endif
+
+#ifndef timestamp_read
+//#define timestamp_read() timestamp_read()
+//inline timestamp_t timestamp_read() { return (timestamp_t)micros(); }
+#define timestamp_read() ((timestamp_t)micros())
+#endif
+
+//------------------------------------------------------------------------------
+
+#ifdef assert
+#else
+#	ifdef NDEBUG
+#		define assert(e) ((void)0)
+#	else
+#		define assert(e) ((e) ? (void)0 : abort())
+#	endif
+#endif
+
+//------------------------------------------------------------------------------
+
+//#define TIMESTAMP_TMAX ((timestamp_t)(1UL<<(sizeof(timestamp_t)*8-1))-1) // 2147483647=0x7FFFFFFF
+// 4'294'967'296 = 1'0000'0000 = [2^32us]
+// 3'600'000'000 =   D693'A400 = [1h]
+//   694'967'296 =   296C'5C00 = [2^32us - 1h = 694.967296s = 11m + 34.967296s]
+// 3'947'483'648 =   EB49'D200
+//   268'435'456 =   1000'0000 = [268.435456s = 4m + 28.435456s]
+//    65'536'000 =    3E8'0000 = [65.536000s = 1m + 5.536000s]
+//     1'000'000 =      F'4240 = [1s]
+//    30'000'000 =    1C9'C380 = [30s]
+// 4'264'951'808 =   FE36'0000 = 1'0000'0000 - 1CA'0000 = [1h + 11m + 4s + 951ms + 808us]
+//    30'015'488 =    1CA'0000 = [30s + 15ms + 488us]
+
+#define TIMESTAMP_DEAD (0x01CA0000) // dead time [30s + 15ms + 488us]
+#define TIMESTAMP_TMAX (0xFE35FFFF) // [1h + 11m + 4s + 951ms + 808us - 1]
+
+#define TIMESTAMP_1US	(1UL)					// [1us]
+#define TIMESTAMP_1MS	(1000*TIMESTAMP_1US)	// [1ms]
+#define TIMESTAMP_1SEC	(1000*TIMESTAMP_1MS)	// [1s]
+#define TIMESTAMP_1MIN	(60*TIMESTAMP_1SEC)		// [1 minute]
+#define TIMESTAMP_1HOUR	(60*TIMESTAMP_1MIN)		// [1 hour]
+
+//------------------------------------------------------------------------------
+
+#define jm_Scheduler_time_read() timestamp_read()
+#define jm_Scheduler_tref_read() (jm_Scheduler::tref)
+#define jm_Scheduler_tref_ival(ival) (jm_Scheduler::tref + ival)
+
+#define jm_Scheduler_time_ge_time(tref, time) ((timestamp_t)(tref - time) < TIMESTAMP_DEAD)
+#define jm_Scheduler_tref_ge_time(time) ((timestamp_t)(jm_Scheduler::tref - time) < TIMESTAMP_DEAD)
+#define jm_Scheduler_tref_ival_ge_time(ival, time) ((timestamp_t)(jm_Scheduler::tref + ival - time) < TIMESTAMP_DEAD)
+
+class jm_Scheduler
+{
+public:
+
+	static timestamp_t tref;			// current scheduler time
+	static jm_Scheduler *first;			// first scheduled coroutine chain
+	static jm_Scheduler *crnt;			// current running coroutine
+
+	static jm_Scheduler *wakeup_first;	// first wakeup coroutine chain
+
+public:
+
+	voidfuncptr_t func;					// address of coroutine function
+	timestamp_t time;					// time of scheduled execution
+	timestamp_t ival;					// interval of cyclic execution
+
+	jm_Scheduler *next;					// next in coroutine chain
+
+	timestamp_t wakeup_time;			// time of first wakeup (may be repeated)
+	jm_Scheduler *wakeup_next;			// next coroutine in wakeup coroutine chain
+	int wakeup_count;					// count of repeated wakeup
+
+	void chain_insert();
+	void chain_remove();
+
+	void wakeup_chain_append();
+	void wakeup_chain_remove();
+
+	bool started;
+	bool stopping;
+	bool yielded;
+
+	jm_Scheduler();
+	~jm_Scheduler();
+
+	operator bool();
+
+	void display(int line);
+
+	static void time_cycle();
+	static void cycle();
+	static void yield();
+//	static void sleep(timestamp_t ival);
+
+	static void delay(unsigned long ms);
+	static void delayMicroseconds(unsigned int us);
+
+	// start coroutine immediately
+	bool start(voidfuncptr_t func); // OK
+
+	// start coroutine immediately and repeat it at fixed interval
+	bool start(voidfuncptr_t func, timestamp_t ival); // OK
+
+	// start coroutine on time and repeat it at fixed interval
+	bool start(voidfuncptr_t func, timestamp_t time, timestamp_t ival); // OK
+
+	// stop coroutine, current or scheduled, remove it from chain
+	void stop();
+
+	// rearm coroutine
+	void rearm();
+
+	// rearm coroutine asynchronously
+	void rearm_async();
+
+	// rearm coroutine and set interval
+	void rearm(timestamp_t ival);
+
+	// rearm coroutine asynchronously and set interval
+	void rearm_async(timestamp_t ival);
+
+//	// rearm coroutine, set time and set next interval
+//	void rearm(timestamp_t time, timestamp_t ival);
+
+	// rearm coroutine, change coroutine function and set interval
+	void rearm(voidfuncptr_t func, timestamp_t ival);
+
+	// rearm coroutine asynchronously, change coroutine function and set interval
+	void rearm_async(voidfuncptr_t func, timestamp_t ival);
+
+//	// rearm coroutine, change coroutine function, set time and set interval
+//	void rearm(voidfuncptr_t func, timestamp_t time, timestamp_t ival);
+
+	// wakeup a scheduled coroutine (maybe repeated)
+	void wakeup();
+
+	// wakeup a scheduled coroutine (maybe repeated but only 1st wakeup_time is recorded)
+	void wakeup(uint32_t wakeup_time);
+
+	// read wakeup count, reset it and remove coroutine from wakeup chain
+	int wakeup_read();
+};
+
+//------------------------------------------------------------------------------
+
+//extern void yield(void);
+
+//------------------------------------------------------------------------------
+
+#endif