ANN: ufarc - state machine lib for uasyncio
Posted: Sat Feb 02, 2019 4:19 pm
Introduction
ufarc is a QP-like framework to help you build an async/concurrent application using hierarchical state machines with message passing and run-to-completion semantics (in less than 500 sloc).
Why use ufarc?
I became a bit disillusioned with CPython's asynchronous syntax in its early days. I was confused on how I was to architect my program when yield was such a clumsy method of flow control. Now, I admit the more recent async/await syntax has greatly improved things, but I still find myself preferring the familiarity of state machines (I learned them in college). State machines let me design an architecture by decomposing the problem by drawing nested boxes (states) and arrows (events). The state machine becomes a class. A state is coded as a method. The framework passes Events (a tuple of signal & data) as an argument to the handler method. This is perfect for embedded programming: nearly all my code is written in compact paragraphs; almost like writing an interrupt handler for each event. I create a state machine for each resource that needs protection against concurrent access. And I code each event handler without worrying about pre-emptive threads, semaphores or deadlock. There's a lot more to the goodness that is state-machine programming that I haven't said here, but I didn't want to ramble too long.
The point is, you can use ufarc to design a concurrent system using state machines and you don't need to know anything about uasyncio. You create state machine classes, start them in their initial state. Then you call ufarc.run_forever() to run uasyncio's event loop.
Honesty
I just got this ported last night. Only half of the code examples run. I'm seeing bugs in the other examples that are a matter of the differences between CPython and MicroPython (and asyncio and uasyncio). But I'm hoping some of you will help me expose the bugs and iron them out.
Backstory
I wrote the farc framework for CPython to help me explore state-machine-oriented programming over the last two years. With farc, I created HeyMac, a 100% CPython app that ran on a raspberry pi, and communicated with GPS over UART, a LoRa modem over SPI and GPIO and provided a layered communications stack... all while running on one Raspbian CPython process. But the Pi was just my prototyping hardware. My ultimate goal is to get HeyMac running on a microcontroller. And that's why I made ufarc (pronounced: you-fark).
ufarc is a QP-like framework to help you build an async/concurrent application using hierarchical state machines with message passing and run-to-completion semantics (in less than 500 sloc).
Why use ufarc?
I became a bit disillusioned with CPython's asynchronous syntax in its early days. I was confused on how I was to architect my program when yield was such a clumsy method of flow control. Now, I admit the more recent async/await syntax has greatly improved things, but I still find myself preferring the familiarity of state machines (I learned them in college). State machines let me design an architecture by decomposing the problem by drawing nested boxes (states) and arrows (events). The state machine becomes a class. A state is coded as a method. The framework passes Events (a tuple of signal & data) as an argument to the handler method. This is perfect for embedded programming: nearly all my code is written in compact paragraphs; almost like writing an interrupt handler for each event. I create a state machine for each resource that needs protection against concurrent access. And I code each event handler without worrying about pre-emptive threads, semaphores or deadlock. There's a lot more to the goodness that is state-machine programming that I haven't said here, but I didn't want to ramble too long.
The point is, you can use ufarc to design a concurrent system using state machines and you don't need to know anything about uasyncio. You create state machine classes, start them in their initial state. Then you call ufarc.run_forever() to run uasyncio's event loop.
Honesty
I just got this ported last night. Only half of the code examples run. I'm seeing bugs in the other examples that are a matter of the differences between CPython and MicroPython (and asyncio and uasyncio). But I'm hoping some of you will help me expose the bugs and iron them out.
Backstory
I wrote the farc framework for CPython to help me explore state-machine-oriented programming over the last two years. With farc, I created HeyMac, a 100% CPython app that ran on a raspberry pi, and communicated with GPS over UART, a LoRa modem over SPI and GPIO and provided a layered communications stack... all while running on one Raspbian CPython process. But the Pi was just my prototyping hardware. My ultimate goal is to get HeyMac running on a microcontroller. And that's why I made ufarc (pronounced: you-fark).