Pointer tutorial image

State Machine Tutorial Pt/3

State Machine tutorial part 3.

In this third part of the state machine tutorial some improvements to the C programming code shown in part 2 will be made, the code is still based on the state machine diagram shown in part 1.

Removing the Global Variable

The first improvement will remove the global variable Current_State, using this as a local variable in the main function.  Firstly we have to declare the function prototype for the StateMachine function as follows:

enum states StateMachine(enum events event, enum states Current_State);

The main function needs to change, so the function call for StateMachine function reflects the change in the function prototype, so it has 2 parameters.

/*****
* 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

	// This line and the way the StateMachine function is called inside the while loop
	//avoids using Current_State as a global variable which improves the code
	enum states Current_State = S_OFF;

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

    return 0;
}

Addtionally a local variable to main is declared enum states Current_State = S_OFF;

Now the StateMachine function has 2 parameters,  enum events event and enum states Current_State;

The enum events event parameter relates to the returned value from the ReadKeyInput function, this is called by the StateMachine function as per the previous code example.

The enum states Current_State parameter returns the value of the Next_State variable inside the StateMachine function.  There is a return Next_State; statement at the end of the StateMachine function, the only other change is to the StateMachine function declaration as with the function prototype ensuring the parameters match.

LookUp Table Structure Improvement

A lookup table contains predefined values, and is often used as it saves valuable clock cycles that would otherwise be spent carrying out a calculation.  In this instance the lookup table is used to simplify the functions called, when a transition from or to a state and when the same state is selected.

There will be individual functions available for execution when entering, exiting and while-in a state.  This makes for a cleaner layout and removes the additional switch case statements in the UponEnter, UponExit and ActionWhileInState functions.  Pointers are used to bring this about as well as a typedef statement.  The code excerpt below shows the 9 additional function prototypes that will be used.

/*****
* Function prototypes
*****/
enum states StateMachine(enum events event, enum states Current_State);
int ReadKeyInput(void);

void State_Enter_OFF(void);   void State_Enter_ON(void);   void State_Enter_PROCESS(void);
void State_InState_OFF(void); void State_InState_ON(void); void State_InState_PROCESS(void);
void State_Exit_OFF(void);    void State_Exit_ON(void);    void State_Exit_PROCESS(void);

The next step is to set-up the typedef and pointer that will be used with the lookup table.

typedef void (* const voidFunc)(void);

voidFunc UponEnter[S_MAX] =          {State_Enter_OFF,   State_Enter_ON,   State_Enter_PROCESS};
voidFunc ActionWhileInState[S_MAX] = {State_InState_OFF, State_InState_ON, State_InState_PROCESS};
voidFunc UponExit[S_MAX] =           {State_Exit_OFF,    State_Exit_ON,    State_Exit_PROCESS};

The line starting with typedef is a typedef for a function pointer, the function this pointer points to expects no parameters and not returning anything to be exact.

The 3 lines that follow are the function pointers, one for each state.  These hold arrays of data that correspond to each state, and point to individual functions that will be actioned when a state transition or the same state is selected.

The third piece of code relevant to this lookup table is found at the bottom of the StateMachine function.

    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
        if (Next_State != S_MAX) UponEnter[Next_State]();
    }
    else // ActionWhileInState is only be called when NOT doing a transition
     {
        if ( event != E_MAX) ActionWhileInState[Current_State]();
    }
    return Next_State;
}

There are 3 function calls at the end of the StateMachine function;

UponExit[Current_State]();  UponEnter[Next_State]();  ActionWhileInState[Current_State]();

So for example the line UponExit[Current_State](); calls the function pointer UponExit[Current_State]();  points to either;

State_Exit_OFF if Current_State is 0  enum states { S_OFF == 0

State_Exit_ON if Current_State is 1  enum states { S_ON == 1

State_Exit_PROCESS if Current_State is 2  enum states { S_PROCESS == 2

There is also an additional else statement that allows ActionWhileInState function, to only be called if the Next_State is equal to the Current_State.

The process that is happening here can be illustrated in a simple table, showing the function/s called depending on the state transition:

State Machine Project Tutorial C Code

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, but if the same number is entered on the keyboard, then no transition occurs and the ActionWhileInState function is only called.

State Machine Project Tutorial C Code

Complete State Machine C Code

The link below contains the zip file with the full state machine C code covered in this third tutorial, 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.2

I would also like to take this opportunity to give a big thanks to Roadrunner84 from the www.43oh.com forums, he has been very helpful and clearly possess a great understanding of the C language.

One thought on “State Machine Tutorial Pt/3”

  1. Another simpler alternative:

    void (* StateController)(void);
    void state1(void);
    void state2(void);

    void main()
    {
    StateController=&state1; //initial state
    while(1)
    {
    (* StateController)();
    }
    }

    void state1(void)
    {
    //do something in state1
    if(if you need to go to state 2 and state 1 related function is complete)
    StateController=&state2;
    else
    StateController=&state1; //im using an else only to show no transition
    }

    void state2(void)
    {
    //do something in state2
    //Keep changing function direction based on state transition
    StateController=&state1;
    }

    You can build on this.

Leave a Reply