This uses the protothreads approach to enable imperative synchronous programming (as promoted by Blech) in pure C.
/* This blinks an LED on every other tick. */
pa_activity (FastBlinker, pa_ctx(), int pin) {
while (true) {
setLED(pin, RED);
pa_pause;
setLED(pin, BLACK);
pa_pause;
}
} pa_activity_end;
/* This blinks an LED on a custom schedule. */
pa_activity (SlowBlinker, pa_ctx_tm(), int pin, unsigned on_ticks, unsigned off_ticks) {
while (true) {
setLED(pin, RED);
pa_delay (on_ticks);
setLED(pin, BLACK);
pa_delay (off_ticks);
}
} pa_activity_end;
/* An activity which delays for a given number of ticks. */
pa_activity (Delay, pa_ctx_tm(), unsigned ticks) {
pa_delay (ticks);
} pa_activity_end;
/* This drives blinking LEDs and preempts them after 3 and 10 ticks. */
pa_activity (Main, pa_ctx_tm(pa_co_res(3); pa_use(Delay); pa_use(FastBlinker); pa_use(SlowBlinker))) {
printf("Begin\n");
/* Blink Fast LED for 3 ticks */
pa_after_abort (3, FastBlinker, 0);
/* Blink both LED for 10 ticks */
pa_co(3) {
pa_with (Delay, 10);
pa_with_weak (FastBlinker, 0);
pa_with_weak (SlowBlinker, 1, 3, 2);
} pa_co_end;
printf("Done\n");
} pa_activity_end;
For a detailed description of the statements, currently refer to the Blech documentation.
pa_pause
: will pause the activity for one tickpa_halt
: will pause the activity foreverpa_await (cond)
: will pause the activity and resume it once cond becomes truepa_delay (ticks)
: will pause the activity for the given number of tickspa_delay_ms (ms)
: will pause the activity for the giveb number of millisecondspa_run (activity, ...)
: runs the given sub-activity until it returnspa_return
: end an activity from within its body - otherwise ends at the end.pa_co(n)
: starts a concurrent section - reserve the number of trails with pa_co_res(num_trails)pa_with (activity, ...)
: runs the given activity concurrently with the others of this sectionpa_with_weak (activity, ...)
: runs the given activity concurrently with the others of this section and can be preemptedpa_when_abort (cond, activity, ...)
: runs the given activity until cond becomes true in a subsequent tick - unless it ends beforepa_when_reset (cond, activity, ...)
: runs the given activity and restarts it when cond becomes true in a subsequen tickpa_when_suspend (cond, activity, ...)
: will suspend the given activity while cond is true and lets it continue when cond is false againpa_after_abort (ticks, activity, ...)
: will abort the given activity after the specified number of tickspa_after_ms_abort (ms, activity, ...)
: will abort the given activity after the specified time in millisecondspa_did_abort (activity)
: reports whether an activity was aborted in the call beforepa_always
: will run code on every tickpa_every (cond)
: will run code everytime cond is truepa_whenever (cond, activity, ...)
: will run the given activity whenever cond is true and abort it if cond turns false
- A medium article about proto_activities can be found here.
- Here is a little robot with
proto_activities
running on three ESP32 nodes. - See running proto_activities code in this online Wokwi simulator.
- Pappe is a sibling project which uses an embedded DSL to allow Blech-style imperative synchronous programming in Swift.