FSM: Programming
Let's try creating code to represent the passcode lock example. Generally, there's a straightforward process to creating most FSMs.
The first step is to declare an enum for the states of the machine.
typedef enum {SX, S2, S25, S253, S2534} passcode_state_t;
Next, declare a static variable with the initial state. The reason why we want this variable to be static is because FSMs will typically be encapsulated in functions. As a result, you want to keep track of the current state of the machine throughout each function call; the state shouldn't be resetting and instead should be static across every function call.
static passcode_state_t currentState = SX;
The next step is to make boolean variables for each output, making sure to also give them default values. This output should not be static.
bool unlocked = false;
Afterward, create an empty switch-case statement, where each state is its own case.
switch (currentState) {
case SX:
break;
case S2:
break;
case S25:
break;
case S253:
break;
case S2534:
break;
}
Now, we implement the transition arcs for each state. Each case should assign output values if they differ from the default and assign the next state.
switch (currentState) {
case SX:
if (guess == 2)
currentState = S2;
break;
case S2:
if (guess == 5)
currentState = S25;
else
currentState = SX;
break;
case S25:
if (guess == 3)
currentState = S253;
else
currentState = SX;
break;
case S253:
if (guess == 4)
currentState = S2534;
unlocked = true;
else
currentState = SX;
break;
case S2534:
currentState = SX;
break;
}
Once the switch-case statement has been evaluated, take any necessary actions from the resulting outputs. For example,
if (unlocked)
openLock();
else
closeLock();
Finally, if the FSM functions utilizes one of the outputs as a return value, return the output value.
return unlocked;
If we put this all together, we could have something like the following:
typedef enum {SX, S2, S25, S253, S2534} passcode_state_t;
int main(void) {
while (1) {
// the getGuessInput() function will halt the program
// until an input is received
int input = getGuessInput();
// passcodeFSM() is the function containing the FSM
bool isUnlocked = passcodeFSM(input);
if (isUnlocked)
playUnlockJingle();
}
}
bool passcodeFSM(int guess) {
static passcode_state_t currentState = SX;
bool unlocked = false;
switch (currentState) {
case SX:
if (guess == 2)
currentState = S2;
break;
case S2:
if (guess == 5)
currentState = S25;
else
currentState = SX;
break;
case S25:
if (guess == 3)
currentState = S253;
else
currentState = SX;
break;
case S253:
if (guess == 4) {
currentState = S2534;
unlocked = true; }
else
currentState = SX;
break;
case S2534:
currentState = SX;
break;
}
if (unlocked)
openLock();
else
closeLock();
return unlocked;
}
Note that this code is not synthesizable on its own. In its current state, many of the functions are not defined and will not compile if you simply copy/paste this into CCS. The intent of this example code is to demonstrate what a typical FSM would look like and how it would be implemented. Instead, use the text above as a reference or skeleton for your FSM.
Nonetheless, we recommend that you debug the above code on your board to get a deeper understanding of how it works. You can download a compilable version of this project from GitHub here.