State Machine Tutorial Pt/2

State Machine tutorial part 2 of 3.

Is this part the C programming code for the basic state machine diagram shown in part 1. All the code presented here was written using the open source software Eclipse IDE, this can be downloaded from here.

Starting at the top of the code and working down, all the main elements will be explained. The complete code can be downloaded at the bottom of this article.

Variables

Firstly we need to define the variables for the state machine. Enum is used instead of another variable type, as it allows a type with a restricted set of values.  So we therefore have enum states and enum events, each with their own set of restricted values, what can also be noted is the states and events correspond directly with those found in the state machine diagram in part 1.  The code excerpt below shows the code for the variables.

/*****
* State definitions, states are the routine the program jumps to, these are prefixed with an 'S' for easy identification
*****/
enum states { S_OFF, S_ON, S_PROCESS, S_MAX };

/*****
* Event definitions, events trigger a transition and are prefixed with an 'E' for easy identification
*****/
enum events { E_OFF, E_ON, E_START, E_MAX };

There is one global variable used in this basic example, Current_State which is used to store the current state machine state outside the state machine function.  The Current_State variable is set to the S_OFF state from the beginning, this enables a predictable outcome when the program is first run.  This variable can be seen in the code extract below.

/*****
* Global variable
*****/
int Current_State = S_OFF;

Function Prototypes

These are used to provide the compiler with the name and arguments of the functions used in the program, they must appear before the function is used in the program.  Each of these functions will be explained in more detail further down this tutorial.

/*****
* Function prototypes
*****/
void UponEnter( int State);
void ActionWhileInState( int State );
void UponExit( int State);
void StateMachine(int event);
int ReadKeyInput(void);

 Main Function

This is where the main program code to be executed is written.  The main is quite short and consists of a continuous while loop, which contains the StateMachine function call.

/*****
* Main function starts here
*****/
int main()
{
	setvbuf(stdout, NULL, _IONBF, 0);	// Lines required as Eclipse has buffer issues when used with Windows and the scanf function
	setvbuf(stderr, NULL, _IONBF, 0);	// Lines required as Eclipse has buffer issues when used with Windows and the scanf function

    while ( Current_State != S_MAX )
    {
		// Function call for the state machine, which then calls the read keys function and waits for the value returned
        StateMachine( ReadKeyInput() );
    }

    return 0;
}

 ReadKeyInput Function

The ReadKeyInput function takes a value entered by a user and then passes this to the StateMachine function.  The ReadKeyInput function uses a local char variable called input, the scanf function forms part of the C library functions and allows user input via the keyboard which is stored in the char variable input.  The variable is then used in the switch case statement, to return an event type pending on the user input.  The code snippet below shows the entire ReadKeyInput function.

/*****
* Read Keys function definition containing the code to execute
*****/
int ReadKeyInput(void)
{
    char input;
    scanf("%c", &input);
    switch (input)
    {
        case '1':
            return E_OFF;
            break;
        case '2':
            return E_ON;
            break;
        case '3':
            return E_START;
            break;
    }
    return E_MAX; //
}

 StateMachine Function

This as it’s name suggests contains the main state machine structure, based around a switch case statement.  When an event is passed to this function by the ReadKeyInput function, firstly a local variable called Next_State is assigned the value held in the variable Current_State, the switch case is then used using the Current_State variable.  So if S_OFF is the value assigned to the Current_State variable, the switch case will open the first case in the sequence which is S_OFF.

Now if the user has entered the number 2 on the keyboard, the event E_ON will be generate by the ReadKeyInput function, this will therefore match up with the event logic inside the nested switch case statement contained within the S_OFF case inside the StateMachine function.  Then the Next_State variable will be assigned the S_ON state.  If key numbers 1 or 2 are pressed E_OFF or E_START will be generated by the ReadKeyInput function, neither of these are valid arguments for the nested switch case statement contained within the S_OFF case, so there will be no change of state and the code performs as per the state machine diagram.  The same logic follows for the S_ON and S_PROCESS cases inside the StateMachine function.  The StateMachine function code can be seen below.

/*****
* State Machine function definition containing the code to execute
*****/
void StateMachine(int event)
{
    int Next_State = Current_State;

    switch ( Current_State )
    {
    case S_OFF:
        switch (event )
        {
            // A transition to the next state will occur here
            case E_ON:
            	Next_State = S_ON;
                break;
        }
        break;
    case S_ON:
        switch (event )
        {
            // A transition to the next state will occur here
            case E_OFF:
            	Next_State = S_OFF;
                break;
            case E_START:
            	Next_State = S_PROCESS;
                break;
        }
        break;
    case S_PROCESS:
        switch (event )
        {
            // A transition to the next state will occur here
        case E_OFF:
        	Next_State = S_OFF;
            break;
        }
        break;
        // The program should never arrive here
		default:
        break;
    }

    if (Next_State != Current_State)
    {
		// Function call for Upon Exit function, it can be omitted but allows extra functionality
        UponExit(Current_State);
		// Function call for Upon Enter function, it can be omitted but allows extra functionality
        UponEnter(Next_State);
        Current_State = Next_State;
    }

    if ( event != E_MAX) ActionWhileInState( Current_State );
}

The final piece of code at the bottom of the StateMachine function allows some additional functionality, firstly the if (Next_State != Current_State) uses the ‘not equal to’ operator, so if there is a state transition, some code can be executed when exiting the current state and entering the next state.

The last statement if ( event != E_MAX) ActionWhileInState( Current_State ); runs the ActionWhileInState function as long as the event is not equal to E_MAX.

UponEnter Function

This function allows custom code to used to execute when entering a new state, the function uses a switch case which is passed the Next_State variable value.  The function can be seen below in the code excerpt.

/*****
* Upon Enter function definition containing the code to execute
*****/
void UponEnter( int State)
{
    switch (State)
    {
    case S_OFF:
        // Custom code here to execute when entering the new state
    	puts("This is the UponEnter function running for the S_OFF state");
		break;
    case S_ON:
		// Custom code here to execute when entering the new state
    	puts("This is the UponEnter function running for the S_ON state");
		break;
    case S_PROCESS:
		// Custom code here to execute when entering the new state
    	puts("This is the UponEnter function running for the S_PROCESS state");
		break;
    }
}

ActionWhileInState Function

This function allows custom code to used to execute while in the current state, the function uses a switch case which is passed the Current_State variable value.  The function can be seen below in the code excerpt.

/*****
* Action While function definition containing the code to execute
*****/
void ActionWhileInState( int State)
{
    switch (State)
    {
    case S_OFF:
		// Custom code here to execute while in the current state
    	puts("Current state S_OFF - ActionWhileInState function");
		break;
    case S_ON:
		// Custom code here to execute while in the current state
    	puts("Current state S_ON - ActionWhileInState function");
		break;
    case S_PROCESS:
		// Custom code here to execute while in the current state
    	puts("Current state S_PROCESS - ActionWhileInState function");
		break;

    }
}

UponExit Function

This function allows custom code to used to execute when exiting the current state, the function uses a switch case which is passed the Current_State variable value.  The function can be seen below in the code excerpt.

/*****
* Upon Exit function definition containing the code to execute
*****/
void UponExit( int State)
{
    switch (State)
    {
    case S_OFF:
        // Custom code here to execute when exiting the current state
    	puts("This is the UponExit function running for the S_OFF state");
		break;
    case S_ON:
		// Custom code here to execute when exiting the current state
    	puts("This is the UponExit function running for the S_ON state");
		break;
    case S_PROCESS:
		// Custom code here to execute when exiting the current state
    	puts("This is the UponExit function running for the S_PROCESS state");
		break;
    }
}

State Machine output

The image below is a screen capture of the console window in Eclipse, this shows the output from the state machine code as numbers are entered from the keyboard.  As shown in the diagram when a transition occurs the UponExit and UponEnter functions are called, as well as the ActionWhileInState function.  If the same number is entered on the keyboard, then no transition occurs and the ActionWhileInState function is only called.  Also the number 4 was entered at the very end, but no transition occurred as this is not a valid argument.

Complete State Machine C Code

The link below contains the zip file with the full state machine C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

State Machine v1.1

Further improvements can still be made to this code but this forms a good starting point in understanding the state machine structure.  In part 3 of this tutorial some of the code improvements will be shown.

Leave a Reply