C - Finite State Machine (FSM) Implementation in C

A Finite State Machine (FSM) is a computational model used to represent the behavior of a system by dividing its operation into a finite number of states. At any given moment, the system exists in one specific state, and it changes from one state to another only when a predefined event or condition occurs. FSMs are widely used in embedded systems, communication protocols, game development, robotics, vending machines, traffic light controllers, and user interface design because they provide a structured and organized way to manage complex program logic.

Instead of writing numerous nested if-else or switch statements throughout a program, an FSM organizes the application's behavior into clearly defined states and transitions. This makes the code easier to understand, maintain, and extend.

Components of a Finite State Machine

An FSM consists of four primary components:

States

A state represents the current condition or mode of operation of a program. Only one state is active at a time.

For example, consider a traffic light system:

  • Red

  • Yellow

  • Green

Each of these represents a separate state.

Events

An event is something that causes the system to move from one state to another.

Examples include:

  • Timer expires

  • Button is pressed

  • Sensor detects an object

  • User logs in

  • Network packet arrives

Transitions

A transition defines how the machine moves from one state to another when an event occurs.

Example:

Current State: Red

Event: Timer expires

Next State: Green

Actions

Actions are operations performed when entering a state, leaving a state, or during a transition.

Example:

Current State: Door Closed

Event: Open Button Pressed

Action:

  • Unlock door

  • Open door

  • Move to Open State


Why Use FSM in C?

C programming is often used in systems where reliability and performance are critical. FSMs help developers:

  • Organize complex program flow.

  • Reduce nested conditional statements.

  • Improve readability.

  • Simplify debugging.

  • Make adding new features easier.

  • Separate logic from implementation.

  • Improve code reusability.


Understanding FSM with a Real-Life Example

Consider an automatic washing machine.

Possible states:

  • Idle

  • Filling Water

  • Washing

  • Rinsing

  • Spinning

  • Completed

Initially:

Idle

When the Start button is pressed:

Idle → Filling Water

When water reaches the required level:

Filling Water → Washing

After washing completes:

Washing → Rinsing

After rinsing:

Rinsing → Spinning

After spinning:

Spinning → Completed

Instead of checking every possible condition repeatedly, the machine simply reacts according to its current state.


Implementing FSM in C

The most common implementation involves:

  • Enumeration for states

  • Enumeration for events

  • Switch-case for state handling

  • Transition logic

Step 1: Define States

typedef enum
{
    RED,
    GREEN,
    YELLOW
} TrafficState;

Step 2: Store Current State

TrafficState currentState = RED;

Step 3: Handle Transitions

void changeState()
{
    switch(currentState)
    {
        case RED:
            printf("Red Light\n");
            currentState = GREEN;
            break;

        case GREEN:
            printf("Green Light\n");
            currentState = YELLOW;
            break;

        case YELLOW:
            printf("Yellow Light\n");
            currentState = RED;
            break;
    }
}

Step 4: Run the Machine

int main()
{
    for(int i=0;i<6;i++)
    {
        changeState();
    }

    return 0;
}

Output:

Red Light
Green Light
Yellow Light
Red Light
Green Light
Yellow Light

The program keeps cycling through the predefined states.


FSM Using Events

Real systems respond to events rather than simply changing states automatically.

Example:

typedef enum
{
    LOCKED,
    UNLOCKED
} DoorState;

typedef enum
{
    INSERT_KEY,
    CLOSE_DOOR
} Event;

State transition function:

void processEvent(Event e)
{
    switch(currentState)
    {
        case LOCKED:
            if(e == INSERT_KEY)
                currentState = UNLOCKED;
            break;

        case UNLOCKED:
            if(e == CLOSE_DOOR)
                currentState = LOCKED;
            break;
    }
}

Here, transitions occur only when the correct event is received.


FSM Using Transition Tables

Large systems often replace lengthy switch statements with transition tables.

Example table:

Current State Event Next State
Locked Key Inserted Unlocked
Unlocked Door Closed Locked

This approach allows transitions to be modified by editing the table rather than changing program logic.


Applications of FSM

Traffic Light Control

States:

  • Red

  • Green

  • Yellow

Transitions occur after timer expiration.


ATM Machine

States:

  • Idle

  • Card Inserted

  • PIN Verification

  • Transaction

  • Cash Dispensed

  • Exit

Each user action moves the machine to another state.


Elevator System

States:

  • Idle

  • Moving Up

  • Moving Down

  • Door Open

  • Door Closed

Button presses and floor sensors trigger transitions.


Login Authentication

States:

  • Waiting

  • Username Entered

  • Password Entered

  • Authenticated

  • Failed

Each user input changes the application's state.


Robot Navigation

States:

  • Searching

  • Moving

  • Avoiding Obstacle

  • Charging

  • Stopped

Sensor readings determine the transitions.


Communication Protocols

Protocols such as TCP and Bluetooth use FSMs internally to manage connection establishment, data transfer, acknowledgments, retransmissions, and connection termination.


Advantages of FSM

A Finite State Machine offers several benefits:

  • Provides a clear structure for program behavior.

  • Simplifies complex decision-making.

  • Improves code readability.

  • Makes maintenance easier by isolating logic into states.

  • Facilitates debugging because each state can be tested independently.

  • Enables easy expansion by adding new states or transitions.

  • Reduces duplicated code.

  • Supports modular and reusable designs.


Limitations of FSM

Despite its usefulness, FSMs also have some limitations:

  • The number of states can grow significantly in very complex systems, making the design harder to manage.

  • Poorly planned state transitions may introduce unexpected behavior.

  • Basic FSMs do not naturally represent parallel or concurrent activities without additional design techniques.

  • Large transition tables can become difficult to maintain if not organized properly.


Best Practices for FSM Implementation in C

When implementing Finite State Machines in C, follow these practices:

  • Use enum to define states and events instead of integer constants for better readability.

  • Keep state-handling code modular by placing each state's logic in separate functions where appropriate.

  • Use descriptive names for states, events, and transitions.

  • Validate events before performing state changes.

  • Document the state diagram before writing code to avoid missing transitions.

  • For large projects, consider using transition tables instead of extensive switch statements.

  • Log state changes during development to simplify debugging.

  • Design states to perform one well-defined responsibility.

Conclusion

Finite State Machines provide a systematic and efficient way to model program behavior by dividing it into clearly defined states and transitions. In C programming, FSMs are particularly valuable for embedded systems, control systems, communication software, and event-driven applications where predictable behavior is essential. By organizing logic around states and events rather than complex conditional structures, developers can create software that is easier to understand, maintain, test, and expand as project requirements evolve.