docs / libflint / statemachine
Table-driven finite state machine with guards, entry/exit callbacks, and transition actions
Structs
SmState
Describes a single state and its optional entry/exit callbacks.
typedef struct {
int id;
void (*entry)(void *ctx, int event);
void (*exit)(void *ctx, int event);
} SmState;
Members:
id: Integer identifying this state. Typically an enum valueentry: Optional callback invoked when the machine enters this state. Receives the user context and the event that caused the transitionexit: Optional callback invoked when the machine leaves this state. Receives the user context and the event that caused the transition
SmTransition
One row of the transition table. Defines what happens when a specific event occurs in a specific state.
typedef struct {
int source;
int event;
int destination;
int (*guard)(void *ctx, int event);
void (*action)(void *ctx, int event);
} SmTransition;
Members:
source: The state this transition applies toevent: The event that triggers this transitiondestination: The state to move toguard: Optional function that must return nonzero for the transition to proceed. IfNULL, the transition is unconditionalaction: Optional function called during the transition, after the source state's exit callback and before the destination state's entry callback
StateMachine
The state machine instance.
typedef struct {
const SmState *state_table;
size_t state_table_count;
const SmTransition *transition_table;
size_t transition_table_count;
int current_state;
void *ctx;
} StateMachine;
Members:
state_table: Pointer to an array ofSmStatedefinitionsstate_table_count: Number of entries instate_tabletransition_table: Pointer to an array ofSmTransitiondefinitionstransition_table_count: Number of entries intransition_tablecurrent_state: The ID of the current statectx: User-provided context pointer passed to all callbacks
Functions
sm_init
Initializes the state machine with the given state and transition tables. The initial_state must match the id of a state in the states array. Returns 0 on success, -1 on error (NULL arguments, zero counts, or invalid initial state).
int sm_init(
StateMachine *sm,
const SmState *states,
size_t state_count,
int initial_state,
const SmTransition *transitions,
size_t transition_count,
void *ctx
);
/* Usage */
enum { ST_IDLE, ST_RUNNING, ST_ERROR, ST_COUNT };
enum { EV_START, EV_STOP, EV_FAULT };
const SmState states[] = {
{ ST_IDLE, on_enter_idle, NULL },
{ ST_RUNNING, on_enter_run, on_exit_run },
{ ST_ERROR, on_enter_err, NULL },
};
const SmTransition transitions[] = {
{ ST_IDLE, EV_START, ST_RUNNING, NULL, NULL },
{ ST_RUNNING, EV_STOP, ST_IDLE, NULL, NULL },
{ ST_RUNNING, EV_FAULT, ST_ERROR, NULL, log_fault },
{ ST_ERROR, EV_STOP, ST_IDLE, guard_cleared, NULL },
};
StateMachine sm;
sm_init(&sm, states, ST_COUNT, ST_IDLE,
transitions, 4, &my_context);
sm_handle_event
Processes an event. Scans the transition table for the first entry matching the current state and event whose guard (if any) returns nonzero. When a match is found, executes in order:
- Source state's
exitcallback - Transition's
actioncallback - State change to
destination - Destination state's
entrycallback
Returns 0 if a transition was taken, 1 if no matching transition was found (state unchanged).
int sm_handle_event(StateMachine *sm, int event);
/* Usage — typical super-loop */
while (1) {
int event = poll_events();
sm_handle_event(&sm, event);
}
Macros
sm_current_state
Returns the current state ID.
#define sm_current_state(sm) ((sm)->current_state)
Design Notes
Transition priority: When multiple transitions match the same state and event (e.g., with different guards), the first match in the table wins. Order your transition table accordingly.
Allocation-free: The state machine performs no dynamic allocation. Both tables can be const and placed in flash/ROM on embedded targets. The StateMachine struct itself can live on the stack or in static memory.
State lookup: States are looked up by id, not by array index. State IDs do not need to be contiguous or zero-based, though contiguous enums are recommended for simplicity.