A hierarchical state machine helps organize complex behaviors by grouping related states inside bigger states. It makes programs easier to understand and manage.
Hierarchical state machine concept in Embedded C
typedef enum {
STATE_TOP,
STATE_A,
STATE_A1,
STATE_A2,
STATE_B
} State;
void handle_event(State *current_state, Event event) {
switch (*current_state) {
case STATE_TOP:
// handle top-level events
break;
case STATE_A:
// handle events common to A and its substates
break;
case STATE_A1:
// handle events specific to A1
break;
case STATE_A2:
// handle events specific to A2
break;
case STATE_B:
// handle events for B
break;
}
}States are organized in a tree-like structure, where some states contain other states.
Events can be handled at different levels, allowing shared behavior.
typedef enum {
STATE_TOP,
STATE_A,
STATE_A1,
STATE_A2
} State;switch (current_state) {
case STATE_A1:
// handle A1 events
break;
case STATE_A2:
// handle A2 events
break;
}This program shows a simple hierarchical state machine with states inside STATE_A. It moves between states based on events and prints the current state changes.
#include <stdio.h> typedef enum { STATE_TOP, STATE_A, STATE_A1, STATE_A2, STATE_B } State; typedef enum { EVENT_GO_A1, EVENT_GO_A2, EVENT_GO_B, EVENT_BACK } Event; void handle_event(State *current_state, Event event) { switch (*current_state) { case STATE_TOP: if (event == EVENT_GO_A1) { *current_state = STATE_A1; printf("Moved to STATE_A1\n"); } else if (event == EVENT_GO_B) { *current_state = STATE_B; printf("Moved to STATE_B\n"); } else { printf("No transition from STATE_TOP\n"); } break; case STATE_A1: if (event == EVENT_GO_A2) { *current_state = STATE_A2; printf("Moved to STATE_A2\n"); } else if (event == EVENT_BACK) { *current_state = STATE_TOP; printf("Returned to STATE_TOP\n"); } else { printf("No transition from STATE_A1\n"); } break; case STATE_A2: if (event == EVENT_BACK) { *current_state = STATE_TOP; printf("Returned to STATE_TOP\n"); } else { printf("No transition from STATE_A2\n"); } break; case STATE_B: if (event == EVENT_BACK) { *current_state = STATE_TOP; printf("Returned to STATE_TOP\n"); } else { printf("No transition from STATE_B\n"); } break; } } int main() { State current_state = STATE_TOP; handle_event(¤t_state, EVENT_GO_A1); // Move to A1 handle_event(¤t_state, EVENT_GO_A2); // Move to A2 handle_event(¤t_state, EVENT_BACK); // Back to TOP handle_event(¤t_state, EVENT_GO_B); // Move to B handle_event(¤t_state, EVENT_BACK); // Back to TOP return 0; }
Hierarchical states reduce repeated code by sharing behavior in parent states.
Transitions can happen between sub-states or back to parent states.
Keep the state tree simple to avoid confusion.
Hierarchical state machines group states inside bigger states for clarity.
They help manage complex behaviors by sharing common actions.
Use events to move between states and sub-states.
Practice
hierarchical state machine in embedded C programming?Solution
Step 1: Understand hierarchical state machine purpose
Hierarchical state machines group related states inside bigger states to simplify complex logic.Step 2: Identify the benefit
This grouping helps share common actions and manage transitions more clearly.Final Answer:
It organizes states into groups, making complex behavior easier to manage. -> Option DQuick Check:
Grouping states = easier management [OK]
- Thinking events are not needed in hierarchical state machines
- Believing states run independently without interaction
- Assuming no transitions are required
Solution
Step 1: Understand enum usage for states
In embedded C, states are often defined as enums. Logical nesting is done by naming and design, not by code nesting.Step 2: Identify correct sub-state definition
typedef enum { STATE_PARENT, STATE_CHILD } State; // with STATE_CHILD nested inside STATE_PARENT logically correctly states that STATE_CHILD is logically nested inside STATE_PARENT, even though enums are flat.Final Answer:
typedef enum { STATE_PARENT, STATE_CHILD } State; // with STATE_CHILD nested inside STATE_PARENT logically -> Option CQuick Check:
Logical nesting, not code nesting [OK]
- Trying to nest enums inside enums (not allowed in C)
- Assuming code blocks define sub-states
- Declaring sub-states as separate enums without relation
EVENT_START occurs in STATE_IDLE?
#define EVENT_START 1
typedef enum { STATE_IDLE, STATE_ACTIVE, STATE_ACTIVE_SUB } State;
State current_state = STATE_IDLE;
void handle_event(int event) {
switch (current_state) {
case STATE_IDLE:
if (event == EVENT_START) {
current_state = STATE_ACTIVE;
printf("Entered ACTIVE state\n");
}
break;
case STATE_ACTIVE:
if (event == EVENT_START) {
current_state = STATE_ACTIVE_SUB;
printf("Entered ACTIVE_SUB state\n");
}
break;
default:
printf("No action\n");
}
}
handle_event(EVENT_START);Solution
Step 1: Check initial state and event
The current_state is STATE_IDLE. The event is EVENT_START.Step 2: Follow switch-case logic for STATE_IDLE
On EVENT_START in STATE_IDLE, current_state changes to STATE_ACTIVE and prints "Entered ACTIVE state".Final Answer:
Entered ACTIVE state -> Option BQuick Check:
STATE_IDLE + EVENT_START = Entered ACTIVE state [OK]
- Assuming it jumps directly to sub-state
- Ignoring initial state value
- Confusing event handling in different states
#define EVENT_GO 1
typedef enum { STATE_TOP, STATE_SUB } State;
State current_state = STATE_TOP;
void handle_event(int event) {
switch (current_state) {
case STATE_TOP:
if (event = EVENT_GO) {
current_state = STATE_SUB;
printf("Moved to SUB state\n");
}
break;
case STATE_SUB:
printf("In SUB state\n");
break;
}
}Solution
Step 1: Examine if condition in STATE_TOP case
The condition uses single '=' which assigns EVENT_GO to event instead of comparing.Step 2: Understand impact of assignment in if
This causes the condition to always be true if EVENT_GO is non-zero, leading to unintended behavior.Final Answer:
Using assignment (=) instead of comparison (==) in if condition -> Option AQuick Check:
Use '==' for comparison, not '=' [OK]
- Confusing assignment and comparison operators
- Ignoring missing default case (not critical here)
- Expecting return in void function
STATE_RUNNING has two sub-states: STATE_RUNNING_FAST and STATE_RUNNING_SLOW. Which approach correctly models this hierarchy and allows shared entry actions for STATE_RUNNING and specific actions for its sub-states?Solution
Step 1: Understand hierarchical state machine design
Parent states group sub-states to share common behavior and allow specific sub-state actions.Step 2: Identify correct coding approach
Defining separate enums for parent and sub-states and using nested switch-case allows shared entry actions for parent and specific actions for sub-states efficiently.Final Answer:
Define separate enums for all states and use nested switch-case to handle parent and sub-states with shared and specific actions. -> Option AQuick Check:
Nested switch-case models hierarchy best [OK]
- Duplicating shared actions in sub-states
- Tracking states separately without hierarchy
- Ignoring parent-child relationship in code
Ready to prove it?
Pass the test and this pattern moves unknown
