|
1 | | -## Finite State Machine (Conditional Statement Implementation) |
| 1 | +# Finite State Machine (FSM) Implementation |
2 | 2 |
|
3 | | -#### FSM Diagram |
4 | | - |
| 3 | +## Overview |
| 4 | +A Finite State Machine (FSM) is a computational model used to design computer programs and digital logic circuits. It consists of a finite number of states, transitions between those states, and actions. FSMs are particularly important in embedded systems for managing system behavior, user interfaces, and protocol implementations. |
5 | 5 |
|
6 | | -#### Usage |
7 | | -``` |
| 6 | +## Key Concepts |
| 7 | + |
| 8 | +### States |
| 9 | +- **Idle State**: Initial state when no card is inserted |
| 10 | +- **Card Inserted State**: State after a card is inserted |
| 11 | +- **PIN Entered State**: State after PIN is entered |
| 12 | +- **Option Selected State**: State after user selects an option |
| 13 | +- **Amount Entered State**: State after amount is entered |
| 14 | + |
| 15 | +### Events |
| 16 | +- **Card Insert Event**: Triggered when a card is inserted |
| 17 | +- **PIN Enter Event**: Triggered when PIN is entered |
| 18 | +- **Option Selection Event**: Triggered when user selects an option |
| 19 | +- **Amount Enter Event**: Triggered when amount is entered |
| 20 | +- **Amount Dispatch Event**: Triggered when amount is dispatched |
| 21 | + |
| 22 | +### Transitions |
| 23 | +The FSM transitions between states based on events. Each transition is handled by a specific event handler function. |
| 24 | + |
| 25 | +## Implementation |
| 26 | + |
| 27 | +### FSM Diagram |
| 28 | + |
| 29 | + |
| 30 | +### Usage |
| 31 | +```bash |
8 | 32 | make |
9 | 33 | ./stateMachine |
10 | 34 | ``` |
11 | 35 |
|
12 | | -#### Code |
| 36 | +### Code Implementation |
| 37 | + |
| 38 | +#### Header File (`state_machine.h`) |
13 | 39 | ```c |
| 40 | +#ifndef STATE_MACHINE_H |
| 41 | +#define STATE_MACHINE_H |
| 42 | + |
14 | 43 | #include <stdio.h> |
15 | 44 | #include <stdlib.h> |
16 | | -//Different state of ATM machine |
17 | | -typedef enum |
18 | | -{ |
19 | | - Idle_State, |
20 | | - Card_Inserted_State, |
21 | | - Pin_Eentered_State, |
22 | | - Option_Selected_State, |
23 | | - Amount_Entered_State, |
| 45 | + |
| 46 | +// System states enumeration |
| 47 | +typedef enum { |
| 48 | + IDLE_STATE, |
| 49 | + CARD_INSERTED_STATE, |
| 50 | + PIN_ENTERED_STATE, |
| 51 | + OPTION_SELECTED_STATE, |
| 52 | + AMOUNT_ENTERED_STATE, |
| 53 | + MAX_STATES |
24 | 54 | } eSystemState; |
25 | | -//Different type events |
26 | | -typedef enum |
27 | | -{ |
28 | | - Card_Insert_Event, |
29 | | - Pin_Enter_Event, |
30 | | - Option_Selection_Event, |
31 | | - Amount_Enter_Event, |
32 | | - Amount_Dispatch_Event |
| 55 | + |
| 56 | +// System events enumeration |
| 57 | +typedef enum { |
| 58 | + CARD_INSERT_EVENT, |
| 59 | + PIN_ENTER_EVENT, |
| 60 | + OPTION_SELECTION_EVENT, |
| 61 | + AMOUNT_ENTER_EVENT, |
| 62 | + AMOUNT_DISPATCH_EVENT, |
| 63 | + MAX_EVENTS |
33 | 64 | } eSystemEvent; |
34 | | -//Prototype of eventhandlers |
35 | | -eSystemState AmountDispatchHandler(void) |
36 | | -{ |
37 | | - return Idle_State; |
| 65 | + |
| 66 | +// Function prototypes |
| 67 | +eSystemState amountDispatchHandler(void); |
| 68 | +eSystemState enterAmountHandler(void); |
| 69 | +eSystemState optionSelectionHandler(void); |
| 70 | +eSystemState enterPinHandler(void); |
| 71 | +eSystemState insertCardHandler(void); |
| 72 | + |
| 73 | +// State machine functions |
| 74 | +void stateMachineInit(void); |
| 75 | +eSystemState processEvent(eSystemState currentState, eSystemEvent event); |
| 76 | +const char* getStateName(eSystemState state); |
| 77 | +const char* getEventName(eSystemEvent event); |
| 78 | + |
| 79 | +#endif // STATE_MACHINE_H |
| 80 | +``` |
| 81 | + |
| 82 | +#### Implementation File (`state_machine.c`) |
| 83 | +```c |
| 84 | +#include "state_machine.h" |
| 85 | + |
| 86 | +// Event handler functions |
| 87 | +eSystemState amountDispatchHandler(void) { |
| 88 | + printf("Amount dispatched. Returning to idle state.\n"); |
| 89 | + return IDLE_STATE; |
38 | 90 | } |
39 | | -eSystemState EnterAmountHandler(void) |
40 | | -{ |
41 | | - return Amount_Entered_State; |
| 91 | + |
| 92 | +eSystemState enterAmountHandler(void) { |
| 93 | + printf("Amount entered successfully.\n"); |
| 94 | + return AMOUNT_ENTERED_STATE; |
42 | 95 | } |
43 | | -eSystemState OptionSelectionHandler(void) |
44 | | -{ |
45 | | - return Option_Selected_State; |
| 96 | + |
| 97 | +eSystemState optionSelectionHandler(void) { |
| 98 | + printf("Option selected successfully.\n"); |
| 99 | + return OPTION_SELECTED_STATE; |
46 | 100 | } |
47 | | -eSystemState EnterPinHandler(void) |
48 | | -{ |
49 | | - return Pin_Eentered_State; |
| 101 | + |
| 102 | +eSystemState enterPinHandler(void) { |
| 103 | + printf("PIN entered successfully.\n"); |
| 104 | + return PIN_ENTERED_STATE; |
50 | 105 | } |
51 | | -eSystemState InsertCardHandler(void) |
52 | | -{ |
53 | | - return Card_Inserted_State; |
| 106 | + |
| 107 | +eSystemState insertCardHandler(void) { |
| 108 | + printf("Card inserted successfully.\n"); |
| 109 | + return CARD_INSERTED_STATE; |
54 | 110 | } |
55 | | -int main(int argc, char *argv[]) |
56 | | -{ |
57 | | - eSystemState eNextState = Idle_State; |
58 | | - eSystemEvent eNewEvent; |
59 | | - char input; |
60 | | - while(1) |
61 | | - { |
62 | | - printf("curState: %d\n", eNextState); |
63 | | - //Read system Events |
64 | | - printf("please enter event\n0 = Card_Insert_Event\n1 = Pin_Enter_Event\n2 = Option_Selection_Event\n3 = Amount_Enter_Event\n4 = Amount_Dispatch_Event\n"); |
65 | | - input = getchar( ); |
66 | | - eSystemEvent eNewEvent = atoi(&input); |
67 | | - switch(eNextState) |
68 | | - { |
69 | | - case Idle_State: |
70 | | - { |
71 | | - if(Card_Insert_Event == eNewEvent) |
72 | | - { |
73 | | - eNextState = InsertCardHandler(); |
| 111 | + |
| 112 | +// State machine processing function |
| 113 | +eSystemState processEvent(eSystemState currentState, eSystemEvent event) { |
| 114 | + switch(currentState) { |
| 115 | + case IDLE_STATE: |
| 116 | + if(event == CARD_INSERT_EVENT) { |
| 117 | + return insertCardHandler(); |
74 | 118 | } |
75 | | - } |
76 | | - break; |
77 | | - case Card_Inserted_State: |
78 | | - { |
79 | | - if(Pin_Enter_Event == eNewEvent) |
80 | | - { |
81 | | - eNextState = EnterPinHandler(); |
| 119 | + break; |
| 120 | + |
| 121 | + case CARD_INSERTED_STATE: |
| 122 | + if(event == PIN_ENTER_EVENT) { |
| 123 | + return enterPinHandler(); |
82 | 124 | } |
83 | | - } |
84 | | - break; |
85 | | - case Pin_Eentered_State: |
86 | | - { |
87 | | - if(Option_Selection_Event == eNewEvent) |
88 | | - { |
89 | | - eNextState = OptionSelectionHandler(); |
| 125 | + break; |
| 126 | + |
| 127 | + case PIN_ENTERED_STATE: |
| 128 | + if(event == OPTION_SELECTION_EVENT) { |
| 129 | + return optionSelectionHandler(); |
90 | 130 | } |
91 | | - } |
92 | | - break; |
93 | | - case Option_Selected_State: |
94 | | - { |
95 | | - if(Amount_Enter_Event == eNewEvent) |
96 | | - { |
97 | | - eNextState = EnterAmountHandler(); |
| 131 | + break; |
| 132 | + |
| 133 | + case OPTION_SELECTED_STATE: |
| 134 | + if(event == AMOUNT_ENTER_EVENT) { |
| 135 | + return enterAmountHandler(); |
98 | 136 | } |
99 | | - } |
100 | | - break; |
101 | | - case Amount_Entered_State: |
102 | | - { |
103 | | - if(Amount_Dispatch_Event == eNewEvent) |
104 | | - { |
105 | | - eNextState = AmountDispatchHandler(); |
| 137 | + break; |
| 138 | + |
| 139 | + case AMOUNT_ENTERED_STATE: |
| 140 | + if(event == AMOUNT_DISPATCH_EVENT) { |
| 141 | + return amountDispatchHandler(); |
106 | 142 | } |
107 | | - } |
108 | | - break; |
| 143 | + break; |
| 144 | + |
109 | 145 | default: |
110 | | - printf("invalid input\n"); |
| 146 | + printf("Invalid state: %d\n", currentState); |
| 147 | + break; |
| 148 | + } |
| 149 | + |
| 150 | + printf("Invalid event %s for state %s\n", getEventName(event), getStateName(currentState)); |
| 151 | + return currentState; |
| 152 | +} |
| 153 | + |
| 154 | +// Utility functions |
| 155 | +const char* getStateName(eSystemState state) { |
| 156 | + static const char* stateNames[] = { |
| 157 | + "IDLE_STATE", |
| 158 | + "CARD_INSERTED_STATE", |
| 159 | + "PIN_ENTERED_STATE", |
| 160 | + "OPTION_SELECTED_STATE", |
| 161 | + "AMOUNT_ENTERED_STATE" |
| 162 | + }; |
| 163 | + return (state < MAX_STATES) ? stateNames[state] : "UNKNOWN_STATE"; |
| 164 | +} |
| 165 | + |
| 166 | +const char* getEventName(eSystemEvent event) { |
| 167 | + static const char* eventNames[] = { |
| 168 | + "CARD_INSERT_EVENT", |
| 169 | + "PIN_ENTER_EVENT", |
| 170 | + "OPTION_SELECTION_EVENT", |
| 171 | + "AMOUNT_ENTER_EVENT", |
| 172 | + "AMOUNT_DISPATCH_EVENT" |
| 173 | + }; |
| 174 | + return (event < MAX_EVENTS) ? eventNames[event] : "UNKNOWN_EVENT"; |
| 175 | +} |
| 176 | +``` |
| 177 | +
|
| 178 | +#### Main Application (`main.c`) |
| 179 | +```c |
| 180 | +#include "state_machine.h" |
| 181 | +
|
| 182 | +int main(int argc, char *argv[]) { |
| 183 | + eSystemState currentState = IDLE_STATE; |
| 184 | + eSystemEvent newEvent; |
| 185 | + char input; |
| 186 | + |
| 187 | + printf("=== ATM State Machine Demo ===\n"); |
| 188 | + printf("Available events:\n"); |
| 189 | + printf("0 = Card Insert Event\n"); |
| 190 | + printf("1 = PIN Enter Event\n"); |
| 191 | + printf("2 = Option Selection Event\n"); |
| 192 | + printf("3 = Amount Enter Event\n"); |
| 193 | + printf("4 = Amount Dispatch Event\n"); |
| 194 | + printf("q = Quit\n\n"); |
| 195 | + |
| 196 | + while(1) { |
| 197 | + printf("Current State: %s\n", getStateName(currentState)); |
| 198 | + printf("Enter event (0-4, q to quit): "); |
| 199 | + |
| 200 | + input = getchar(); |
| 201 | + getchar(); // Consume newline |
| 202 | + |
| 203 | + if(input == 'q' || input == 'Q') { |
| 204 | + printf("Exiting...\n"); |
111 | 205 | break; |
112 | 206 | } |
| 207 | + |
| 208 | + newEvent = (eSystemEvent)atoi(&input); |
| 209 | + |
| 210 | + if(newEvent >= 0 && newEvent < MAX_EVENTS) { |
| 211 | + eSystemState nextState = processEvent(currentState, newEvent); |
| 212 | + if(nextState != currentState) { |
| 213 | + printf("State transition: %s -> %s\n", |
| 214 | + getStateName(currentState), getStateName(nextState)); |
| 215 | + currentState = nextState; |
| 216 | + } |
| 217 | + } else { |
| 218 | + printf("Invalid event. Please enter 0-4 or q to quit.\n"); |
| 219 | + } |
| 220 | + |
| 221 | + printf("\n"); |
113 | 222 | } |
| 223 | + |
114 | 224 | return 0; |
115 | 225 | } |
| 226 | +``` |
| 227 | + |
| 228 | +#### Makefile |
| 229 | +```makefile |
| 230 | +CC = gcc |
| 231 | +CFLAGS = -Wall -Wextra -std=c99 |
| 232 | +TARGET = stateMachine |
| 233 | +SOURCES = main.c state_machine.c |
| 234 | +HEADERS = state_machine.h |
116 | 235 |
|
| 236 | +$(TARGET): $(SOURCES) $(HEADERS) |
| 237 | + $(CC) $(CFLAGS) -o $(TARGET) $(SOURCES) |
117 | 238 |
|
| 239 | +clean: |
| 240 | + rm -f $(TARGET) |
| 241 | + |
| 242 | +.PHONY: clean |
118 | 243 | ``` |
119 | | -#### Reference |
120 | | -https://aticleworld.com/state-machine-using-c/ |
| 244 | + |
| 245 | +## Common Interview Questions |
| 246 | + |
| 247 | +1. **What is a Finite State Machine?** |
| 248 | + - A computational model with a finite number of states and transitions |
| 249 | + - Used for modeling behavior in embedded systems |
| 250 | + - Consists of states, events, and transitions |
| 251 | + |
| 252 | +2. **What are the advantages of using FSMs?** |
| 253 | + - Clear and predictable behavior |
| 254 | + - Easy to debug and maintain |
| 255 | + - Modular design |
| 256 | + - Suitable for real-time systems |
| 257 | + |
| 258 | +3. **How would you implement an FSM in C?** |
| 259 | + - Use enums for states and events |
| 260 | + - Implement state transition table or switch statements |
| 261 | + - Create event handler functions |
| 262 | + - Use a main loop to process events |
| 263 | + |
| 264 | +4. **What are the different types of FSMs?** |
| 265 | + - **Moore Machine**: Output depends only on current state |
| 266 | + - **Mealy Machine**: Output depends on current state and input |
| 267 | + |
| 268 | +5. **How would you handle invalid state transitions?** |
| 269 | + - Add error handling in transition logic |
| 270 | + - Log invalid transitions |
| 271 | + - Return to a safe state or error state |
| 272 | + |
| 273 | +## Advanced Topics |
| 274 | + |
| 275 | +### State Machine Patterns |
| 276 | +1. **Hierarchical State Machines**: States can contain sub-states |
| 277 | +2. **Nested State Machines**: States can be state machines themselves |
| 278 | +3. **Parallel State Machines**: Multiple state machines running concurrently |
| 279 | + |
| 280 | +### Implementation Considerations |
| 281 | +- **Memory efficiency**: Use lookup tables for large state machines |
| 282 | +- **Performance**: Optimize transition logic for real-time systems |
| 283 | +- **Maintainability**: Use clear naming conventions and documentation |
| 284 | +- **Testing**: Create comprehensive test cases for all transitions |
| 285 | + |
| 286 | +## Resources |
| 287 | +- [State Machine Using C - AticleWorld](https://aticleworld.com/state-machine-using-c/) |
| 288 | +- [Finite State Machines in Embedded Systems](https://embeddedartistry.com/blog/2018/07/12/an-introduction-to-finite-state-machines/) |
| 289 | +- [State Machine Design Patterns](https://www.state-machine.com/doc/concepts.html) |
0 commit comments