State Machine¶
Introduction¶
This document describes the State Machine component of the EzEmbedded Framework.
The State Machine component provides a lightweight, event-driven hierarchical state machine implementation suitable for embedded systems. It enables developers to model complex system behavior using well-defined states and transitions.
What this component does:
Provides a structured way to implement finite state machines
Supports entry, action, and exit functions for each state
Handles event-driven state transitions via an event queue
Supports hierarchical state machines (sub-state machines)
Allows data sharing between states via a user-defined data pointer
What this component does NOT do:
Does not provide automatic code generation from state diagrams
Does not support orthogonal regions (parallel states)
Does not implement history states
Use cases:
Protocol implementations (communication protocols, handshake sequences)
Device control logic (power management, mode switching)
User interface navigation
Workflow and process control in embedded applications
Component’s structure¶
The State Machine component is composed of two main structures:
ezState_t - Represents a single state with the following elements:
name: Human-readable state name for debuggingaction: Function executed repeatedly while in this stateenter: Function executed once when entering this stateexit: Function executed once when leaving this statehandle_event: Function to process incoming eventssub_sm: Pointer to a nested sub-state machine (optional)
ezStateMachine_t - Represents the state machine itself:
curr_state: Pointer to the currently active statenext_state: Pointer to the next state (used during transitions)events: Ring buffer storing pending eventsdata: User-defined data pointer shared between states
The component also provides helper macros for defining states:
INIT_STATE(state_name, sub_state_machine): Declares and initializes a stateDEFINE_ACTION_FUNCTION(state_name): Declares an action functionDEFINE_ENTRY_FUNCTION(state_name): Declares an entry functionDEFINE_EXIT_FUNCTION(state_name): Declares an exit functionDEFINE_EVENT_HANDLER_FUNCTION(state_name): Declares an event handler
Component’s behavior¶
External Behavior¶
The state machine exposes the following API functions:
ezSM_Init(): Initializes the state machine with an initial state and event bufferezSM_Run(): Gives processing time to the state machine (call periodically)ezSM_SetEvent(): Pushes a new event to the state machine’s event queueezSM_ClearAllEvents(): Clears all pending events from the queueezSM_SetState(): Forces a state transition to a specific stateezSM_GetCurrState(): Returns a pointer to the current state
Internal Behavior¶
The state machine follows this execution model during ezSM_Run():
Event Processing: If the current state has an event handler and events are pending, the handler is called with the oldest event. The handler may return a new state to trigger a transition.
Action Execution: If no state change occurred from event handling:
If a sub-state machine exists,
ezSM_Run()is called recursively on itOtherwise, the state’s action function is executed
The action function may return a new state to trigger a transition
State Transition: If a next state is determined:
The current state’s
exitfunction is called (if defined)The exit function can override the next state if an error occurs
The new state’s
enterfunction is called (if defined)The enter function can redirect to another state (e.g., for error handling)
State Transition Diagram:
flowchart TD
Start([ezSM_Run]) --> EventPending{Event pending?}
EventPending -->|Yes| HandleEvent[handle_event]
EventPending -->|No| SubSMExists{Sub-SM exists?}
SubSMExists -->|Yes| RunSubSM[ezSM_Run sub]
SubSMExists -->|No| Action[action]
HandleEvent --> StateChanged{State changed?}
RunSubSM --> StateChanged
Action --> StateChanged
StateChanged -->|Yes| Transition["exit -> enter"]
StateChanged -->|No| Done([Done])
Transition --> Done
Data Flow¶
The following diagram illustrates how data flows through the state machine:
flowchart TD
subgraph Application
SetEvent["ezSM_SetEvent()"]
Run["ezSM_Run()"]
GetState["ezSM_GetCurrState()"]
end
subgraph SM["ezStateMachine_t"]
EventQueue["Event Queue\n(RingBuffer)"]
States["curr_state\nnext_state"]
Data["data (void*)\n(user-defined struct)"]
end
subgraph State["ezState_t"]
HandleEvent["handle_event(event)\n► Returns next state or NULL"]
Action["action(sm)\n► Returns next state or NULL"]
Enter["enter(sm)\n► Initializes state, may redirect"]
Exit["exit(sm)\n► Cleanup, may redirect on error"]
SubSM["sub_sm\n(optional nested SM)"]
end
SetEvent --> EventQueue
Run --> States
States --> GetState
EventQueue --> HandleEvent
States --> Action
Data --> Enter
Data --> Exit
Action --> SubSM
Data exchange between states:
States share data through the
sm->datapointerThis pointer is set during
ezSM_Init()and remains constantStates can cast it to the appropriate structure type to access shared data
Event flow:
External code calls
ezSM_SetEvent()to push events to the queueEvents are stored in a ring buffer (FIFO order)
During
ezSM_Run(), events are popped and processed byhandle_event()The event handler returns a new state pointer or NULL (no transition)
Component’s data type¶
Function Pointer Types¶
-
type ezSM_DoFunction¶
Function executed repeatedly while the state machine is in a state.
- Param sm:
Pointer to the state machine
- Return:
Pointer to the next state, or NULL if no state change
-
type ezSM_EntryFunction¶
Function executed once when entering a new state.
- Param sm:
Pointer to the state machine
- Return:
Pointer to redirect state, or NULL to stay in current state
-
type ezSM_ExitFunction¶
Function executed once when exiting the current state.
- Param sm:
Pointer to the state machine
- Return:
Pointer to override next state, or NULL to proceed normally
-
type ezSM_EventHandler¶
Function to handle incoming events.
- Param event:
The event to be handled (uint8_t)
- Return:
Pointer to the next state, or NULL if event doesn’t cause transition
Structures¶
-
struct ezState¶
Represents a single state in the state machine.
- Member name:
State name string for debugging (can be NULL)
- Member action:
Pointer to the action function (can be NULL)
- Member enter:
Pointer to the entry function (can be NULL)
- Member exit:
Pointer to the exit function (can be NULL)
- Member handle_event:
Pointer to the event handler (can be NULL)
- Member sub_sm:
Pointer to a sub-state machine (can be NULL)
-
struct ezStateMachine¶
Represents the state machine instance.
- Member curr_state:
Pointer to the currently active state
- Member next_state:
Pointer to the next state during transitions
- Member events:
Ring buffer for storing pending events
- Member data:
User-defined data pointer for inter-state communication
Constants¶
-
MAX_SUPPORTED_STATE¶
Maximum number of supported states (0xFF = 255)