An event-driven state machine helps a program react to different events by changing its behavior step-by-step. It keeps track of what the program is doing and what should happen next.
Event-driven state machine in Embedded C
typedef enum {
STATE_IDLE,
STATE_WORKING,
STATE_ERROR
} State;
typedef enum {
EVENT_START,
EVENT_STOP,
EVENT_FAIL
} Event;
State current_state = STATE_IDLE;
void handle_event(Event event) {
switch (current_state) {
case STATE_IDLE:
if (event == EVENT_START) {
current_state = STATE_WORKING;
}
break;
case STATE_WORKING:
if (event == EVENT_STOP) {
current_state = STATE_IDLE;
} else if (event == EVENT_FAIL) {
current_state = STATE_ERROR;
}
break;
case STATE_ERROR:
if (event == EVENT_STOP) {
current_state = STATE_IDLE;
}
break;
}
}States and events are usually defined as enums for clarity.
The event handler changes the current state based on the event and current state.
typedef enum { STATE_OFF, STATE_ON } State;
typedef enum { EVENT_TOGGLE } Event;
State current_state = STATE_OFF;
void handle_event(Event event) {
if (event == EVENT_TOGGLE) {
if (current_state == STATE_OFF) {
current_state = STATE_ON;
} else {
current_state = STATE_OFF;
}
}
}typedef enum { STATE_LOCKED, STATE_UNLOCKED } State;
typedef enum { EVENT_ENTER_CODE, EVENT_TIMEOUT } Event;
State current_state = STATE_LOCKED;
void handle_event(Event event) {
switch (current_state) {
case STATE_LOCKED:
if (event == EVENT_ENTER_CODE) {
current_state = STATE_UNLOCKED;
}
break;
case STATE_UNLOCKED:
if (event == EVENT_TIMEOUT) {
current_state = STATE_LOCKED;
}
break;
}
}This program starts in IDLE state. When it receives a START event, it moves to WORKING. Then a FAIL event moves it to ERROR. Finally, a STOP event returns it to IDLE. Each transition prints what happened.
#include <stdio.h> typedef enum { STATE_IDLE, STATE_WORKING, STATE_ERROR } State; typedef enum { EVENT_START, EVENT_STOP, EVENT_FAIL } Event; State current_state = STATE_IDLE; void handle_event(Event event) { switch (current_state) { case STATE_IDLE: if (event == EVENT_START) { current_state = STATE_WORKING; printf("Transition: IDLE -> WORKING\n"); } break; case STATE_WORKING: if (event == EVENT_STOP) { current_state = STATE_IDLE; printf("Transition: WORKING -> IDLE\n"); } else if (event == EVENT_FAIL) { current_state = STATE_ERROR; printf("Transition: WORKING -> ERROR\n"); } break; case STATE_ERROR: if (event == EVENT_STOP) { current_state = STATE_IDLE; printf("Transition: ERROR -> IDLE\n"); } break; } } int main() { printf("Initial state: IDLE\n"); handle_event(EVENT_START); // Start working handle_event(EVENT_FAIL); // Fail occurs handle_event(EVENT_STOP); // Stop and go to idle return 0; }
Always define clear states and events to avoid confusion.
Keep the event handler simple and focused on changing states.
Print statements help debug state changes during development.
An event-driven state machine changes behavior based on events and current state.
Use enums to name states and events clearly.
Handle events with a switch or if-else to update the current state.
Practice
Solution
Step 1: Understand the concept of event-driven state machine
An event-driven state machine changes its behavior depending on the current state and the events it receives.Step 2: Compare options with the concept
To change behavior based on events and current state correctly describes this behavior. Other options describe unrelated concepts.Final Answer:
To change behavior based on events and current state -> Option AQuick Check:
Event-driven state machine = change behavior by events [OK]
- Thinking state machines just run code sequentially
- Confusing state machines with data storage
- Assuming state machines only do math
Solution
Step 1: Identify proper enum syntax in embedded C
Using typedef enum with named states is the standard and clear way to define states.Step 2: Check options for correctness and clarity
The typedef enum syntax is the preferred choice for type safety and readability. Using separate ints, #defines, or string arrays lacks these benefits and is less idiomatic.Final Answer:
typedef enum {STATE_IDLE, STATE_RUN, STATE_STOP} State; -> Option CQuick Check:
Use enum typedef for states [OK]
- Using #define instead of enum for states
- Using strings instead of enums for states
- Not using typedef with enum
current_state after handle_event(EVENT_START) is called?typedef enum {STATE_IDLE, STATE_RUN, STATE_STOP} State;
typedef enum {EVENT_START, EVENT_STOP} Event;
State current_state = STATE_IDLE;
void handle_event(Event e) {
switch(current_state) {
case STATE_IDLE:
if (e == EVENT_START) current_state = STATE_RUN;
break;
case STATE_RUN:
if (e == EVENT_STOP) current_state = STATE_STOP;
break;
case STATE_STOP:
break;
}
}
handle_event(EVENT_START);Solution
Step 1: Check initial state and event
The initial state is STATE_IDLE. The event passed is EVENT_START.Step 2: Follow the switch-case logic
In STATE_IDLE, if event is EVENT_START, current_state changes to STATE_RUN.Final Answer:
STATE_RUN -> Option BQuick Check:
EVENT_START in STATE_IDLE moves to STATE_RUN [OK]
- Ignoring event condition inside the case
- Assuming state changes without event match
- Thinking code has syntax errors
typedef enum {STATE_IDLE, STATE_RUN} State;
typedef enum {EVENT_START, EVENT_STOP} Event;
State current_state = STATE_IDLE;
void handle_event(Event e) {
switch(current_state) {
case STATE_IDLE:
if (e = EVENT_START) current_state = STATE_RUN;
break;
case STATE_RUN:
if (e == EVENT_STOP) current_state = STATE_IDLE;
break;
}
}Solution
Step 1: Inspect the if condition in STATE_IDLE case
The condition uses 'if (e = EVENT_START)', which assigns EVENT_START to e instead of comparing.Step 2: Understand the effect of assignment in condition
Assignment returns the assigned value, which is non-zero, so condition is always true, causing incorrect state changes.Final Answer:
Using assignment '=' instead of comparison '==' in if condition -> Option DQuick Check:
Use '==' for comparison, not '=' [OK]
- Confusing '=' and '==' in conditions
- Ignoring missing default case (not critical here)
- Assuming all states must be defined
STATE_PAUSE and event EVENT_PAUSE to the existing state machine. Which code snippet correctly updates the handle_event function to handle pausing from STATE_RUN and resuming back to STATE_RUN from STATE_PAUSE?Solution
Step 1: Understand desired transitions
From STATE_RUN, EVENT_PAUSE should move to STATE_PAUSE. From STATE_PAUSE, EVENT_PAUSE should resume to STATE_RUN.Step 2: Check each option for correct transitions
case STATE_RUN: if (e == EVENT_PAUSE) current_state = STATE_PAUSE; else if (e == EVENT_STOP) current_state = STATE_IDLE; break; case STATE_PAUSE: if (e == EVENT_PAUSE) current_state = STATE_RUN; break; matches these transitions exactly. Other options assign wrong states or events.Final Answer:
case STATE_RUN: if (e == EVENT_PAUSE) current_state = STATE_PAUSE; else if (e == EVENT_STOP) current_state = STATE_IDLE; break; case STATE_PAUSE: if (e == EVENT_PAUSE) current_state = STATE_RUN; break; -> Option AQuick Check:
Pause toggles between RUN and PAUSE states [OK]
- Assigning wrong states on pause/resume events
- Confusing EVENT_PAUSE with EVENT_STOP
- Missing else if for multiple events
Ready to prove it?
Pass the test and this pattern moves unknown
