Event-driven state machine in Embedded C - Time & Space Complexity
We want to understand how the time taken by an event-driven state machine changes as it processes more events.
How does the number of events affect the work done inside the state machine?
Analyze the time complexity of the following code snippet.
// Simple event-driven state machine
void process_event(int event) {
switch(current_state) {
case STATE_IDLE:
if(event == EVENT_START) {
current_state = STATE_RUNNING;
}
break;
case STATE_RUNNING:
if(event == EVENT_STOP) {
current_state = STATE_IDLE;
}
break;
}
}
This code changes the state based on the event received, using a switch-case structure.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The switch-case checks the current state and event once per call.
- How many times: Once for each event processed.
Each event causes one check and possibly a state change.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 checks |
| 100 | 100 checks |
| 1000 | 1000 checks |
Pattern observation: The work grows directly with the number of events processed.
Time Complexity: O(n)
This means the time taken grows linearly with the number of events handled.
[X] Wrong: "The state machine does a lot of work for each event, so time grows faster than the number of events."
[OK] Correct: Each event triggers only a simple check and possibly a state change, so work per event stays constant.
Understanding how event-driven state machines scale helps you design responsive and efficient embedded systems.
"What if the state machine had nested loops inside each state to process events? How would the time complexity change?"
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
