33A low-memory, fast-switching, cooperative multitasking library using
44stackless coroutines on Arduino platforms.
55
6- Version: 0.2 (2018-10-02 )
6+ Version: 0.2.1 (2019-07-01 )
77
88This library is currently in "beta" status. I'm releasing it through the Arduino
99Library Manager to solicit feedback from interested users. Send me an email or
@@ -35,11 +35,12 @@ their life cycle:
3535* ` COROUTINE_END() ` : must occur at the end of the coroutine body
3636* ` COROUTINE_YIELD() ` : yields execution back to the caller, often
3737 ` CoroutineScheduler ` but not necessarily
38- * ` COROUTINE_AWAIT(condition) ` : yield until ` condition ` become ` true `
38+ * ` COROUTINE_AWAIT(condition) ` : yield until ` condition ` becomes ` true `
3939* ` COROUTINE_DELAY(millis) ` : yields back execution for ` millis ` . The ` millis `
4040 parameter is defined as a ` uint16_t ` .
4141* ` COROUTINE_DELAY_SECONDS(loopCounter, seconds) ` : yields back execution for
42- ` seconds ` . The ` seconds ` parameter is defined as a ` uint16_t ` .
42+ ` seconds ` . The maximum value of ` seconds ` is determined by ` loopCounter `
43+ which can be of any integer type.
4344* ` COROUTINE_LOOP() ` : convenience macro that loops forever
4445* ` COROUTINE_CHANNEL_WRITE(channel, value) ` : writes a value to a ` Channel `
4546* ` COROUTINE_CHANNEL_READ(channel, value) ` : reads a value from a ` Channel `
@@ -56,7 +57,8 @@ others (in my opinion of course):
5657 * 1.1-2.0 microseconds on Teensy 3.2 (depending on compiler settings)
5758 * ~ 1.7 microseconds on a ESP8266
5859 * ~ 0.5 microseconds on a ESP32
59- * uses "computed goto" feature of GCC to avoid the
60+ * uses the [ computed goto] ( https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html )
61+ feature of the GCC compiler (also supported by Clang) to avoid the
6062 [ Duff's Device] ( https://en.wikipedia.org/wiki/Duff%27s_device ) hack
6163 * allows ` switch ` statemens in the coroutines
6264* C/C++ macros eliminate boilerplate code and make the code easy to read
@@ -66,11 +68,16 @@ others (in my opinion of course):
6668
6769Some limitations are:
6870* A ` Coroutine ` cannot return any values.
69- * A ` Coroutine ` is stackless cannot preserve local stack varaibles
71+ * A ` Coroutine ` is stackless and therefore cannot preserve local stack variables
7072 across multiple calls. Often the class member variables or function static
7173 variables are reasonable substitutes.
74+ * Coroutines are currently designed to be statically allocated, not dynamically
75+ created and destroyed. This is mostly because dynamic memory allocation
76+ on an 8-bit microcontroller with 2kB of RAM should probably be avoided.
77+ Dynamically created coroutines may be added in the future for 32-bit
78+ microcontrollers which have far more memory.
7279* A ` Channel ` is an experimental feature and has limited features. It is
73- currently an unbuffered, synchrronized channel. It can be used by only one
80+ currently an unbuffered, synchronized channel. It can be used by only one
7481 reader and one writer.
7582
7683After I had completed most of this library, I discovered that I had essentially
@@ -108,7 +115,7 @@ COROUTINE(printHello) {
108115 COROUTINE_BEGIN();
109116
110117 Serial.print(F("Hello, "));
111- COROUTINE_DELAY(1000 );
118+ COROUTINE_DELAY(2000 );
112119
113120 COROUTINE_END();
114121}
@@ -126,6 +133,7 @@ void setup() {
126133 delay(1000);
127134 Serial.begin(115200);
128135 while (!Serial); // Leonardo/Micro
136+ pinMode(LED, OUTPUT);
129137}
130138
131139void loop() {
@@ -135,7 +143,7 @@ void loop() {
135143}
136144```
137145
138- This prints "Hello, ", then waits one second , and then prints "World!".
146+ This prints "Hello, ", then waits 2 seconds , and then prints "World!".
139147At the same time, the LED blinks on and off.
140148
141149The [HelloScheduler.ino](examples/HelloScheduler) sketch implements the same
@@ -151,6 +159,7 @@ void setup() {
151159 delay(1000);
152160 Serial.begin(115200);
153161 while (!Serial); // Leonardo/Micro
162+ pinMode(LED, OUTPUT);
154163
155164 CoroutineScheduler::setup();
156165}
@@ -402,7 +411,7 @@ define a coroutine with a `mDelayCounter` member variable, and use the
402411``` C++
403412class MyCoroutine : public Coroutine {
404413 public:
405- virtual int runCoroutine() override {
414+ int runCoroutine() override {
406415 ...
407416 COROUTINE_DELAY_SECONDS(mDelayCounter, 1000);
408417 ...
@@ -626,7 +635,7 @@ class InnerCoroutine: public Coroutine {
626635 public:
627636 InnerCoroutine(..) { ...}
628637
629- virtual int runCoroutine override {
638+ int runCoroutine override {
630639 COROUTINE_BEGIN();
631640 ...
632641 COROUTINE_END();
@@ -640,7 +649,7 @@ class OuterCoroutine: public Coroutine {
640649 ...
641650 }
642651
643- virtual int runCoroutine override {
652+ int runCoroutine override {
644653 // No COROUTINE_BEGIN() and COROUTINE_END() needed if this simply
645654 // delegates to the InnerCoroutine.
646655 mInner.runCoroutine();
@@ -859,7 +868,7 @@ described in the next section to be more useful.
859868
860869### Manual Coroutines
861870
862- An manual coroutine is a custom coroutine whose body of the coroutine (i.e
871+ A manual coroutine is a custom coroutine whose body of the coroutine (i.e
863872the`runCoroutine()` method) is defined manually and the coroutine object is also
864873instantiated manually, instead of using the `COROUTINE()` macro. This is useful
865874if the coroutine has external dependencies which need to be injected into the
@@ -875,7 +884,7 @@ class ManualCoroutine : public Coroutine {
875884 }
876885
877886 private:
878- virtual int runCoroutine() override {
887+ int runCoroutine() override {
879888 COROUTINE_BEGIN();
880889 // insert coroutine code here
881890 COROUTINE_END();
@@ -1077,7 +1086,7 @@ class Writer: public Coroutine {
10771086 public:
10781087 Writer(...) {...}
10791088
1080- virtual int runCoroutine() override {
1089+ int runCoroutine() override {
10811090 static int i;
10821091 COROUTINE_BEGIN();
10831092 for (i = 0; i < 9; i++) {
@@ -1095,7 +1104,7 @@ class Reader: public Coroutine {
10951104 public
10961105 Reader(...) {...}
10971106
1098- virtual int runCoroutine() override {
1107+ int runCoroutine() override {
10991108 COROUTINE_LOOP() {
11001109 Message message;
11011110 COROUTINE_CHANNEL_READ(mChannel, message);
@@ -1146,7 +1155,7 @@ and a channel between them to communicate:
11461155
11471156* Only a single AceRoutine `Coroutine` can write to a `Channel`.
11481157* Only a single AceRoutine `Coroutine` can read from a `Channel`.
1149- * There is equivalent of a
1158+ * There is no equivalent of a
11501159 [Go Lang select statement](https:// gobyexample.com/select), so the coroutine
11511160 cannot wait for multiple channels at the same time.
11521161* There is no buffered channel type.
@@ -1264,11 +1273,12 @@ In other words, you can create 100 `Coroutine` instances and they would use only
12641273
12651274The ` CoroutineScheduler ` consumes only 2 bytes of memory no matter how many
12661275coroutines are created. That's because it depends on a singly-linked list whose
1267- pointers live on the ` Coroutine ` object, not in the ` CoroutineScheduler ` .
1276+ pointers live on the ` Coroutine ` object, not in the ` CoroutineScheduler ` . But
1277+ the code for the class increases flash memory usage by about 150 bytes.
12681278
12691279The ` Channel ` object requires 2 copies of the parameterized ` <T> ` type so its
12701280size is equal to ` 1 + 2 * sizeof(T) ` , rounded to the nearest memory alignment
1271- boundary (i.e. 12 for a 32-bit processor).
1281+ boundary (i.e. a total of 12 bytes for a 32-bit processor).
12721282
12731283### CPU
12741284
@@ -1282,23 +1292,28 @@ This library was developed and tested using:
12821292* [ ESP8266 Arduino Core 2.4.2] ( https://arduino-esp8266.readthedocs.io/en/2.4.2/ )
12831293* [ arduino-esp32] ( https://github.com/espressif/arduino-esp32 )
12841294
1285- I used MacOS 10.13.3 and Ubuntu 17.10 for most of my development.
1295+ I used MacOS 10.13.3 and Ubuntu 18.04 for most of my development.
12861296
12871297The library is tested on the following hardware before each release:
12881298
12891299* Arduino Nano clone (16 MHz ATmega328P)
12901300* Arduino Pro Micro clone (16 MHz ATmega32U4)
1291- * Teensy 3.2 (72 MHz ARM Cortex-M4)
12921301* NodeMCU 1.0 clone (ESP-12E module, 80 MHz ESP8266)
12931302* ESP32 dev board (ESP-WROOM-32 module, 240 MHz dual core Tensilica LX6)
12941303
12951304I will occasionally test on the following hardware as a sanity check:
12961305
1306+ * Teensy 3.2 (72 MHz ARM Cortex-M4)
1307+ * Teensy LC (48 MHz ARM Cortex-M0+)
12971308* Arduino UNO R3 clone (16 MHz ATmega328P)
12981309* Arduino Pro Mini clone (16 MHz ATmega328P)
1299- * Teensy LC (48 MHz ARM Cortex-M0+)
13001310* ESP-01 (ESP-01 module, 80 MHz ESP8266)
13011311
1312+ The library has been verified to work on Linux or MacOS (using both g++ and
1313+ clang++ compilers) using the
1314+ [ unitduino] ( https://github.com/bxparks/AUnit/tree/develop/unitduino ) emulation
1315+ layer.
1316+
13021317## Changelog
13031318
13041319See [ CHANGELOG.md] ( CHANGELOG.md ) .
@@ -1310,12 +1325,11 @@ See [CHANGELOG.md](CHANGELOG.md).
13101325## Feedback and Support
13111326
13121327If you have any questions, comments, bug reports, or feature requests, please
1313- file a GitHub ticket or send me an email. I'd love to hear about how this
1314- software and its documentation can be improved. Instead of forking the
1315- repository to modify or add a feature for your own projects, let me have a
1316- chance to incorporate the change into the main repository so that your external
1317- dependencies are simpler and so that others can benefit. I can't promise that I
1318- will incorporate everything, but I will give your ideas serious consideration.
1328+ file a GitHub ticket instead of emailing me unless the content is sensitive.
1329+ (The problem with email is that I cannot reference the email conversation when
1330+ other people ask similar questions later.) I'd love to hear about how this
1331+ software and its documentation can be improved. I can't promise that I will
1332+ incorporate everything, but I will give your ideas serious consideration.
13191333
13201334## Authors
13211335
0 commit comments