Basics Programming Model
Hornet protocol stack is implemented as a single-thread state machine. This programming model fits perfectly on both MCU based RTOS and POSIX systems.
Hornet is written in C. We currently use GNU Arm Embedded.
Main Thread and Driver Threads
A thread in Hornet is either a “main thread” or a “driver thread”.
- The “main thread” drives a state machine of the stack and business logic of your hardware.
- There can be more than one “driver thread” that drives the hardware peripheral state machines.
- Every thread shall follow the “poll-sleep-interrupt model.”
“main thread” and “driver threads” are all state machines. But they are logically different state machines.
Execution Model
Each thread shall follow the execution model of poll-sleep-interrupt, we will go into details later.
Thread == Task
In this document, “Thread” is also called “Task.” They are interchangeable.
Main Thread
Main thread shall be treated differently in that,
- It drives the main business logic.
- It drives one iteration of poll(), go to sleep, and wait to be interrupted from sleep.
- It shall have a lower thread priority compared with driver threads.
- Every time a drive thread wakes from sleep, it almost certainly generates a state change for main thread.
In current implementation, the main thread is the FreeRTOS idle task, which has the lowest task priority. But it may change in the future without changing the API.
Driver Threads
Driver threads usually drives a particular peripheral hardware and generates events for main thread.
For example, in Hornet stack, there is a task that drives the MAC layer logic. The MAC task works with the RF hardware to receive wireless packets and manages sending outgoing packets with CSMA/CD algorithm.
Poll-Sleep-Interrupt
In general, the execution flow works as an infinite loop:
poll() -> sleep() -> interrupt -> poll() -> sleep() -> interrupt ...
Please note both poll() and sleep() here are pseudo functions.
Interrupt is a hardware event that wakes up the execution from sleep.
poll() function
poll() function is the key part. poll() drives a state machine.
In Hornet, the poll() for main thread and drivers threads are logically different.
- Main Thread - poll() will re-evaluate the entire state machine on any state change event.
- Driver Threads - poll() generates state change events for main thread.
Note, for every thread,
- poll() also determines the next sleep interval, i.e. “timed sleep”.
Interrupt
Interrupt is generated by hardware.
- User actions - For example, a user pressed a button on a wireless remote control.
- A new wireless message is receiver from MAC driver.
- A sensor reading is changed.
- Note a sleep can be timed-sleep. If no other event happens during sleep, the hardware timer will generate a hardware interrupt.
- “Timer up“ is also considered a state change!
Technically, sleep is always woken up by interrupt.
Interrupts will almost certainly cause a state change, otherwise the developer shall not instruct the device to subscribe the interrupt.
When an interrupt happens, the execution wakes up from sleep state immediately and poll() will be called to re-evaluate state changes and possible trigger further actions.
Low Power
The design and programming paradigm is automatically optimized for low power devices that run on battery for years.
For more details, read “Power Management and Sleep”.