Skip to content

Commit 256dfc3

Browse files
authored
Merge pull request #31 from bxparks/develop
merge v1.3.1 into master
2 parents 9c698d1 + 205469a commit 256dfc3

File tree

98 files changed

+2006
-764
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+2006
-764
lines changed

CHANGELOG.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
# Changelog
22

33
* Unreleased
4+
* 1.3.1 (2021-06-02)
5+
* Bring back `COROUTINE_DELAY_MICROS()` and `COROUTINE_DELAY_SECONDS(),
6+
with an alternate implemenation that increases flash and static memory
7+
*only* if they are used.
8+
* The `Coroutine` itself knows whether it is delaying in units of
9+
milliseconds, microseconds, or seconds, based on its continuation
10+
point.
11+
* Make `CoroutineScheduler::runCoroutine()` always call into
12+
`Coroutine::runCoroutine()` when the `Coroutine::mStatus` is delaying,
13+
instead of preemptively trying to figure out if the delay has expired.
14+
* `Coroutine` does not need a runtime `mDelayType` descriminator.
15+
* The result is that the code to support `COROUTINE_DELAY_MICROS()` and
16+
`COROUTINE_DELAY_SECONDS()` is not pulled into the program if they are
17+
not used.
418
* 1.3.0 (2021-06-02)
519
* Activate GitHub Discussions for the project.
620
* **Potentially Breaking**: Change `Coroutine` destructor from virtual to
@@ -12,7 +26,7 @@
1226
* **Potentially Breaking**: Lift `Coroutine` into `CoroutineTemplate` class.
1327
Lift `CoroutineScheduler` into `CoroutineSchedulerTemplate` class.
1428
* Define `Coroutine` to be `CoroutineTemplate<ClockInterface>`, almost
15-
* fully backwards compatible with previous implementation.
29+
fully backwards compatible with previous implementation.
1630
* Define `CoroutineScheduler` to be
1731
`CoroutineSchedulerTemplate<Coroutine>`, almost fully backwards
1832
compatible with previous implementation.

README.md

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ their life cycle:
3939
* `COROUTINE_AWAIT(condition)`: yield until `condition` becomes `true`
4040
* `COROUTINE_DELAY(millis)`: yields back execution for `millis`. The `millis`
4141
parameter is defined as a `uint16_t`.
42+
* `COROUTINE_DELAY_MICROS(micros)`: yields back execution for `micros`. The
43+
`micros` parameter is defined as a `uint16_t`.
44+
* `COROUTINE_DELAY_SECONDS(seconds)`: yields back execution for
45+
`seconds`. The `seconds` parameter is defined as a `uint16_t`.
4246
* `COROUTINE_LOOP()`: convenience macro that loops forever
4347
* `COROUTINE_CHANNEL_WRITE(channel, value)`: writes a value to a `Channel`
4448
* `COROUTINE_CHANNEL_READ(channel, value)`: reads a value from a `Channel`
@@ -64,16 +68,16 @@ others (in my opinion of course):
6468
* ~1.2 microseconds on a 16 MHz ATmega328P
6569
* ~0.4 microseconds on a 48 MHz SAMD21
6670
* ~0.3 microseconds on a 72 MHz STM32
67-
* ~0.4 microseconds on a 80 MHz ESP8266
68-
* ~0.03 microseconds on a 240 MHz ESP32
71+
* ~0.3 microseconds on a 80 MHz ESP8266
72+
* ~0.1 microseconds on a 240 MHz ESP32
6973
* ~0.17 microseconds on 96 MHz Teensy 3.2 (depending on compiler
7074
settings)
7175
* Coroutine Scheduling (use `CoroutineScheduler::loop()`):
72-
* ~5.2 microseconds on a 16 MHz ATmega328P
73-
* ~1.9 microseconds on a 48 MHz SAMD21
74-
* ~1.4 microseconds on a 72 MHz STM32
75-
* ~1.1 microseconds on a 80 MHz ESP8266
76-
* ~0.3 microseconds on a 240 MHz ESP32
76+
* ~5.5 microseconds on a 16 MHz ATmega328P
77+
* ~1.3 microseconds on a 48 MHz SAMD21
78+
* ~0.9 microseconds on a 72 MHz STM32
79+
* ~0.6 microseconds on a 80 MHz ESP8266
80+
* ~0.2 microseconds on a 240 MHz ESP32
7781
* ~0.5 microseconds on 96 MHz Teensy 3.2 (depending on compiler
7882
settings)
7983
* uses the [computed goto](https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html)
@@ -106,7 +110,7 @@ AceRoutine is a self-contained library that works on any platform supporting the
106110
Arduino API (AVR, Teensy, ESP8266, ESP32, etc), and it provides a handful of
107111
additional macros that can reduce boilerplate code.
108112

109-
**Version**: 1.3 (2021-06-02)
113+
**Version**: 1.3.1 (2021-06-02)
110114

111115
**Changelog**: [CHANGELOG.md](CHANGELOG.md)
112116

@@ -501,45 +505,69 @@ etc) for a handful of AceRoutine features. Here are some highlights:
501505
**Arduino Nano (8-bits)**
502506
503507
```
504-
+--------------------------------------------------------------+
505-
| functionality | flash/ ram | delta |
506-
|---------------------------------+--------------+-------------|
507-
| Baseline | 606/ 11 | 0/ 0 |
508-
|---------------------------------+--------------+-------------|
509-
| One Delay Function | 654/ 13 | 48/ 2 |
510-
| Two Delay Functions | 714/ 15 | 108/ 4 |
511-
|---------------------------------+--------------+-------------|
512-
| One Coroutine | 840/ 30 | 234/ 19 |
513-
| Two Coroutines | 1010/ 47 | 404/ 36 |
514-
|---------------------------------+--------------+-------------|
515-
| Scheduler, One Coroutine | 946/ 32 | 340/ 21 |
516-
| Scheduler, Two Coroutines | 1058/ 43 | 452/ 32 |
517-
|---------------------------------+--------------+-------------|
518-
| Blink Function | 938/ 14 | 332/ 3 |
519-
| Blink Coroutine | 1154/ 30 | 548/ 19 |
520-
+--------------------------------------------------------------+
508+
+------------------------------------------------------------------+
509+
| functionality | flash/ ram | delta |
510+
|-------------------------------------+--------------+-------------|
511+
| Baseline | 400/ 11 | 0/ 0 |
512+
|-------------------------------------+--------------+-------------|
513+
| One Delay Function | 450/ 13 | 50/ 2 |
514+
| Two Delay Functions | 508/ 15 | 108/ 4 |
515+
|-------------------------------------+--------------+-------------|
516+
| One Coroutine | 628/ 30 | 228/ 19 |
517+
| Two Coroutines | 796/ 47 | 396/ 36 |
518+
|-------------------------------------+--------------+-------------|
519+
| One Coroutine (micros) | 596/ 30 | 196/ 19 |
520+
| Two Coroutines (micros) | 732/ 47 | 332/ 36 |
521+
|-------------------------------------+--------------+-------------|
522+
| One Coroutine (seconds) | 724/ 30 | 324/ 19 |
523+
| Two Coroutines (seconds) | 920/ 47 | 520/ 36 |
524+
|-------------------------------------+--------------+-------------|
525+
| Scheduler, One Coroutine | 742/ 32 | 342/ 21 |
526+
| Scheduler, Two Coroutines | 904/ 49 | 504/ 38 |
527+
|-------------------------------------+--------------+-------------|
528+
| Scheduler, One Coroutine (micros) | 710/ 32 | 310/ 21 |
529+
| Scheduler, Two Coroutines (micros) | 840/ 49 | 440/ 38 |
530+
|-------------------------------------+--------------+-------------|
531+
| Scheduler, One Coroutine (seconds) | 838/ 32 | 438/ 21 |
532+
| Scheduler, Two Coroutines (seconds) | 1028/ 49 | 628/ 38 |
533+
|-------------------------------------+--------------+-------------|
534+
| Blink Function | 546/ 14 | 146/ 3 |
535+
| Blink Coroutine | 752/ 30 | 352/ 19 |
536+
+------------------------------------------------------------------+
521537
```
522538
523539
**ESP8266 (32-bits)**
524540
525541
```
526-
+--------------------------------------------------------------+
527-
| functionality | flash/ ram | delta |
528-
|---------------------------------+--------------+-------------|
529-
| Baseline | 256924/26800 | 0/ 0 |
530-
|---------------------------------+--------------+-------------|
531-
| One Delay Function | 256988/26808 | 64/ 8 |
532-
| Two Delay Functions | 257052/26808 | 128/ 8 |
533-
|---------------------------------+--------------+-------------|
534-
| One Coroutine | 257104/26820 | 180/ 20 |
535-
| Two Coroutines | 257264/26844 | 340/ 44 |
536-
|---------------------------------+--------------+-------------|
537-
| Scheduler, One Coroutine | 257152/26828 | 228/ 28 |
538-
| Scheduler, Two Coroutines | 257232/26844 | 308/ 44 |
539-
|---------------------------------+--------------+-------------|
540-
| Blink Function | 257424/26816 | 500/ 16 |
541-
| Blink Coroutine | 257556/26836 | 632/ 36 |
542-
+--------------------------------------------------------------+
542+
+------------------------------------------------------------------+
543+
| functionality | flash/ ram | delta |
544+
|-------------------------------------+--------------+-------------|
545+
| Baseline | 256924/26800 | 0/ 0 |
546+
|-------------------------------------+--------------+-------------|
547+
| One Delay Function | 256988/26808 | 64/ 8 |
548+
| Two Delay Functions | 257052/26808 | 128/ 8 |
549+
|-------------------------------------+--------------+-------------|
550+
| One Coroutine | 257104/26820 | 180/ 20 |
551+
| Two Coroutines | 257264/26844 | 340/ 44 |
552+
|-------------------------------------+--------------+-------------|
553+
| One Coroutine (micros) | 257136/26820 | 212/ 20 |
554+
| Two Coroutines (micros) | 257296/26844 | 372/ 44 |
555+
|-------------------------------------+--------------+-------------|
556+
| One Coroutine (seconds) | 257136/26820 | 212/ 20 |
557+
| Two Coroutines (seconds) | 257312/26844 | 388/ 44 |
558+
|-------------------------------------+--------------+-------------|
559+
| Scheduler, One Coroutine | 257152/26828 | 228/ 28 |
560+
| Scheduler, Two Coroutines | 257280/26844 | 356/ 44 |
561+
|-------------------------------------+--------------+-------------|
562+
| Scheduler, One Coroutine (micros) | 257168/26828 | 244/ 28 |
563+
| Scheduler, Two Coroutines (micros) | 257312/26844 | 388/ 44 |
564+
|-------------------------------------+--------------+-------------|
565+
| Scheduler, One Coroutine (seconds) | 257168/26828 | 244/ 28 |
566+
| Scheduler, Two Coroutines (seconds) | 257328/26844 | 404/ 44 |
567+
|-------------------------------------+--------------+-------------|
568+
| Blink Function | 257424/26816 | 500/ 16 |
569+
| Blink Coroutine | 257556/26836 | 632/ 36 |
570+
+------------------------------------------------------------------+
543571
```
544572
545573
Comparing `Blink Function` and `Blink Coroutine` is probably the most
@@ -567,7 +595,7 @@ Arduino Nano:
567595
|---------------------+--------+-------------+--------|
568596
| EmptyLoop | 10000 | 1.700 | 0.000 |
569597
| DirectScheduling | 10000 | 2.900 | 1.200 |
570-
| CoroutineScheduling | 10000 | 6.900 | 5.200 |
598+
| CoroutineScheduling | 10000 | 7.200 | 5.500 |
571599
+---------------------+--------+-------------+--------+
572600
```
573601
@@ -577,9 +605,9 @@ ESP8266:
577605
+---------------------+--------+-------------+--------+
578606
| Functionality | iters | micros/iter | diff |
579607
|---------------------+--------+-------------+--------|
580-
| EmptyLoop | 10000 | 0.100 | 0.000 |
581-
| DirectScheduling | 10000 | 0.500 | 0.400 |
582-
| CoroutineScheduling | 10000 | 1.200 | 1.100 |
608+
| EmptyLoop | 10000 | 0.200 | 0.000 |
609+
| DirectScheduling | 10000 | 0.500 | 0.300 |
610+
| CoroutineScheduling | 10000 | 0.800 | 0.600 |
583611
+---------------------+--------+-------------+--------+
584612
```
585613

USER_GUIDE.md

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ See the [README.md](README.md) for installation instructions and other
44
background information. This document describes how to use the library once it
55
is installed.
66

7-
**Version**: 1.3 (2021-06-02)
7+
**Version**: 1.3.1 (2021-06-02)
88

99
## Table of Contents
1010

@@ -87,6 +87,10 @@ The following macros are available to hide a lot of boilerplate code:
8787
* `COROUTINE_AWAIT(condition)`: yields until `condition` become `true`
8888
* `COROUTINE_DELAY(millis)`: yields back execution for `millis`. The maximum
8989
allowable delay is 32767 milliseconds.
90+
* `COROUTINE_DELAY_MICROS(micros)`: yields back execution for `micros`. The
91+
maximum allowable delay is 32767 microseconds.
92+
* `COROUTINE_DELAY_SECONDS(seconds)`: yields back execution for `seconds`. The
93+
maximum allowable delay is 32767 seconds.
9094
* `COROUTINE_LOOP()`: convenience macro that loops forever, replaces
9195
`COROUTINE_BEGIN()` and `COROUTINE_END()`
9296
* `COROUTINE_CHANNEL_WRITE()`: writes a message to a `Channel`
@@ -277,9 +281,12 @@ while (!condition) COROUTINE_YIELD();
277281
<a name="Delay"></a>
278282
### Delay
279283

284+
**Delay Milliseconds**
285+
280286
The `COROUTINE_DELAY(millis)` macro yields back control to other coroutines
281-
until `millis` milliseconds have elapsed. The following waits for 100
282-
milliseconds:
287+
until `millis` milliseconds have elapsed. This is analogous to the built-in
288+
Arduino `delay()` function, except that this is non-blocking. The following
289+
waits for 100 milliseconds:
283290

284291
```C++
285292
COROUTINE(waitMillis) {
@@ -291,26 +298,80 @@ COROUTINE(waitMillis) {
291298
}
292299
```
293300
294-
The `millis` argument is a `uint16_t`, a 16-bit unsigned integer, which reduces
301+
The `millis` argument is a `uint16_t`, a 16-bit unsigned integer, which saves
295302
the size of each coroutine instance by 4 bytes (8-bit processors) or 8 bytes
296-
(32-bit processors). However, the actual maximum delay is limited to 32767
297-
milliseconds to avoid overflow situations if the other coroutines in the system
298-
take too much time for their work before returning control to the waiting
299-
coroutine. With this limit, the other coroutines have as much as 32767
300-
milliseconds before it must yield, which should be more than enough time for any
301-
conceivable situation. In practice, coroutines should complete their work within
302-
several milliseconds and yield control to the other coroutines as soon as
303-
possible.
304-
305-
For delays longer than 32767 milliseconds, we can use an explicit for-loop. For
306-
example, to delay for 100,000 seconds, we can do this:
303+
(32-bit processors) compared to using an `uint32_t`. The largest number that
304+
can be represented by a `uint16_t` is 65535, but the actual maximum delay is
305+
limited to 32767 milliseconds to avoid overflow situations if the other
306+
coroutines in the system take too much time for their work before returning
307+
control to the waiting coroutine. With this limit, the other coroutines have as
308+
much as 32767 milliseconds before it must yield, which should be more than
309+
enough time for any conceivable situation. In practice, coroutines should
310+
complete their work within several milliseconds and yield control to the other
311+
coroutines as soon as possible.
312+
313+
**Delay Microseconds**
314+
315+
On faster microcontrollers, it might be useful to yield for microseconds using
316+
the `COROUTINE_DELAY_MICROS(delayMicros)`. The following example waits for 300
317+
microseconds:
318+
319+
```C++
320+
COROUTINE(waitMicros) {
321+
COROUTINE_BEGIN();
322+
...
323+
COROUTINE_DELAY_MICROS(300);
324+
...
325+
COROUTINE_END();
326+
}
327+
```
328+
This macro has a number constraints:
329+
330+
* The maximum delay is 32767 micros.
331+
* All other coroutines in the program *must* yield within 32767 microsecond,
332+
otherwise the internal timing variable will overflow and an incorrect delay
333+
will occur.
334+
* The accuracy of `COROUTINE_DELAY_MICROS()` is not guaranteed because the
335+
overhead of context switching and checking the delay's expiration may
336+
consume a significant portion of the requested delay in microseconds.
337+
338+
**Delay Seconds**
339+
340+
For delays greater than 32767 milliseconds, we can use the
341+
`COROUTINE_DELAY_SECONDS(seconds)` convenience macro. The following example
342+
waits for 200 seconds:
343+
344+
```C++
345+
COROUTINE(waitSeconds) {
346+
COROUTINE_BEGIN();
347+
...
348+
COROUTINE_DELAY_SECONDS(200);
349+
...
350+
COROUTINE_END();
351+
}
352+
```
353+
354+
This macro has some constraints and caveats:
355+
356+
* The maximum number of seconds is 32767 seconds.
357+
* The delay is implemented using the `millis()` clock divided by 1000.
358+
* On 8-bit processors without hardware division instruction, the software
359+
division consumes CPU time and flash memory, about 100 bytes on an AVR.
360+
* The `unsigned long` returned by `millis()` rolls over every
361+
4294967.296 seconds (49.7 days). During that rollover, the
362+
`COROUTINE_DELAY_SECONDS()` will return 0.704 seconds too early. If the
363+
delay value is relatively large, e.g. 100 seconds, this inaccuracy
364+
probably won't matter too much.
365+
366+
We can also use an explicit for-loop. For example, to delay for 1000 seconds, we
367+
can loop 100 times over a `COROUTINE_DELAY()` of 10 seconds, like this:
307368
308369
```C++
309370
COROUTINE(waitThousandSeconds) {
310371
static uint16_t i;
311372
312373
COROUTINE_BEGIN();
313-
for (i = 0; i < 10000; i++) {
374+
for (i = 0; i < 100; i++) {
314375
COROUTINE_DELAY(10000); // 10 seconds
315376
}
316377
...

docs/doxygen.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ PROJECT_NAME = "AceRoutine"
3838
# could be handy for archiving the generated documentation or if some version
3939
# control system is used.
4040

41-
PROJECT_NUMBER = 1.3.0
41+
PROJECT_NUMBER = 1.3.1
4242

4343
# Using the PROJECT_BRIEF tag one can provide an optional one line description
4444
# for a project that appears at the top of each page and should give viewer a

docs/html/AceRoutine_8h_source.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<tr style="height: 56px;">
2323
<td id="projectalign" style="padding-left: 0.5em;">
2424
<div id="projectname">AceRoutine
25-
&#160;<span id="projectnumber">1.3.0</span>
25+
&#160;<span id="projectnumber">1.3.1</span>
2626
</div>
2727
<div id="projectbrief">A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.</div>
2828
</td>

docs/html/Channel_8h_source.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<tr style="height: 56px;">
2323
<td id="projectalign" style="padding-left: 0.5em;">
2424
<div id="projectname">AceRoutine
25-
&#160;<span id="projectnumber">1.3.0</span>
25+
&#160;<span id="projectnumber">1.3.1</span>
2626
</div>
2727
<div id="projectbrief">A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.</div>
2828
</td>

0 commit comments

Comments
 (0)