SMF supports defining a hierarchy of states. For example, the network module's states can be graphically described as follows:
In the diagram, the black dots with arrows indicate initial transitions.
In this case, the initial state of the machine is set to the top-level STATE_RUNNING state. In the state definitions, initial transitions are configured such that the state machine ends up in STATE_DISCONNECTED_SEARCHING when first initialized.
In SMF, a single state is defined using the SMF_CREATE_STATE macro. You can specify the following parameters:
- Entry function: Called when entering the state.
- Run function: Called when processing a message while in the state.
- Exit function: Called when leaving the state.
- Parent state: Another state to which this state is subordinate.
- Initial state transition: Another state to transition to immediately after entry.
The following shows the definitions of all the states in the Network module from app/src/modules/network/network.c, with parent states and initial transitions as shown in the diagram:
static const struct smf_state states[] = {
[STATE_RUNNING] =
SMF_CREATE_STATE(state_running_entry, state_running_run, NULL,
NULL, /* No parent state */
&states[STATE_DISCONNECTED]),
[STATE_DISCONNECTED] =
SMF_CREATE_STATE(state_disconnected_entry, state_disconnected_run, NULL,
&states[STATE_RUNNING],
&states[STATE_DISCONNECTED_SEARCHING]),
[STATE_DISCONNECTED_IDLE] =
SMF_CREATE_STATE(NULL, state_disconnected_idle_run, NULL,
&states[STATE_DISCONNECTED],
NULL), /* No initial transition */
[STATE_DISCONNECTED_SEARCHING] =
SMF_CREATE_STATE(state_disconnected_searching_entry,
state_disconnected_searching_run, NULL,
&states[STATE_DISCONNECTED],
NULL), /* No initial transition */
[STATE_CONNECTED] =
SMF_CREATE_STATE(state_connected_entry, state_connected_run, NULL,
&states[STATE_RUNNING],
NULL), /* No initial transition */
[STATE_DISCONNECTING] =
SMF_CREATE_STATE(state_disconnecting_entry, state_disconnecting_run, NULL,
&states[STATE_RUNNING],
NULL), /* No initial transition */
};