Thread: Structs with a state machine

  1. #1
    Registered User
    Join Date
    Dec 2015
    Posts
    112

    Structs with a state machine

    I'm working on making a state machine with a bunch of structs.

    Each struct will contain things like
    Number of Allowable state changes
    What state changes are allowed
    Timeout of current state
    What state to change to when timeout occurs
    Delay before state change happens
    etc.

    The control loop will have some sort of logic that is common to all the states and use a pointer to point to a different state struct.

    Is this a common practice since I'm mostly seeing examples with a table and in my case I have a variable number of states I can jump to.

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Why not make a small (runnable) example with three states to demonstrate what you mean?

  3. #3
    Registered User
    Join Date
    Dec 2015
    Posts
    68
    Just something simple to keep track at what state and when to restart/stop as don't allow other functions/irq to change state but set these flags only.

    Code:
    typedef struct StateTag                    
    {   
        char state;  
        char delay;
        char timeout;
        char init          : 1;   
        char restart       : 1;   
        char stop          : 1;
        char flag          : 1;
    
    } statestruct;
    extern statestruct machine1;
    Last edited by tonyp12; 03-03-2016 at 07:24 PM.

  4. #4
    Registered User
    Join Date
    Dec 2015
    Posts
    112
    This is a very simple example I got working.

    I use the struct to keep track of what is a valid state jump and the memory location of that state. My real application is I have different states with different responses and timeouts. If it was more complicated I may have used function pointers, but I can just cycle through a loop as such with each state.

    Yes I know there is memory cleanup, etc. I'm just getting the state machine concept down.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    
    
    typedef enum State
    {
        State1,
        State2,
        State3,
        StateNum}
    State;
    
    
    typedef struct StateData
    {
        State CurrentState;
        int NumOfNextStates;
        State *PossibleNextStates;
        struct StateData **StatePtr;
        bool TimeoutFlag;
    }StateData;
    
    
    void State1CreateInit(StateData **s);
    void State2CreateInit(StateData **s);
    void State3CreateInit(StateData **s);
    
    
    int main()
    {
        //StateMachine[0] = malloc(sizeof(StateMachine));
        bool Quit = false;
        char sResp;
        StateData **StateMachine;
        StateData *CurrentState;
    
    
        StateMachine = malloc(StateNum * sizeof(*StateMachine));
        for(int i = 0; i < StateNum; i++)
        {
            StateMachine[i] = malloc(sizeof(*StateMachine[i]));
        }
    
    
        State1CreateInit(StateMachine);
        State2CreateInit(StateMachine);
        State3CreateInit(StateMachine);
    
    
        CurrentState = StateMachine[State1];
    
    
        while(!Quit)
        {
            printf("Current State is %d. Enter desired state:\n", CurrentState->CurrentState);
            sResp = getchar();
    
    
            for(int i = 0; i < CurrentState->NumOfNextStates; i++)
            {
                if(CurrentState->PossibleNextStates[i] == (sResp - '0'))
                {
                    CurrentState = CurrentState->StatePtr[i];
                    break;
                }
            }
            if(sResp == 'q')
                Quit = true;
        }
    
    
        return 0;
    }
    
    
    void State1CreateInit(StateData **s)
    {
        s[State1]->CurrentState = State1;
        s[State1]->NumOfNextStates = 2;
    
    
        s[State1]->PossibleNextStates = malloc(s[State1]->NumOfNextStates * sizeof(*s[State1]->PossibleNextStates));
        s[State1]->StatePtr = malloc(s[State1]->NumOfNextStates * sizeof(*s[State1]->StatePtr));
    
    
        s[State1]->PossibleNextStates[0] = State2;
        s[State1]->PossibleNextStates[1] = State3;
    
    
        s[State1]->StatePtr[0] = s[State2];
        s[State1]->StatePtr[1] = s[State3];
    
    
        s[State1]->TimeoutFlag = false;
    
    
        return;
    }
    
    
    void State2CreateInit(StateData **s)
    {
        s[State2]->CurrentState = State2;
        s[State2]->NumOfNextStates = 1;
    
    
        s[State2]->PossibleNextStates = malloc(s[State2]->NumOfNextStates * sizeof(*s[State2]->PossibleNextStates));
        s[State2]->StatePtr = malloc(s[State2]->NumOfNextStates * sizeof(*s[State2]->StatePtr));
    
    
        s[State2]->PossibleNextStates[0] = State3;
    
    
        s[State2]->StatePtr[0] = s[State3];
    
    
        s[State2]->TimeoutFlag = false;
    
    
        return;
    }
    
    
    void State3CreateInit(StateData **s)
    {
        s[State3]->CurrentState = State3;
        s[State3]->NumOfNextStates = 1;
    
    
        s[State3]->PossibleNextStates = malloc(s[State3]->NumOfNextStates * sizeof(*s[State3]->PossibleNextStates));
        s[State3]->StatePtr = malloc(s[State3]->NumOfNextStates * sizeof(*s[State3]->StatePtr));
    
    
        s[State3]->PossibleNextStates[0] = State1;
    
    
        s[State3]->StatePtr[0] = s[State1];
    
    
        s[State3]->TimeoutFlag = false;
    
    
        return;
    }

  5. #5
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Seem a little overcomplicated.
    No need to store a pointer to the next state when you're already storing the index.
    Your StateCreateInit functions can be combined:
    I couldn't abide your gargantuan variable names so I shortened them.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <stdarg.h>
    
    typedef enum State {
        State0,
        State1,
        State2,
        NumStates
    } State;
    
    typedef struct StateData {
        State  state;
        int    numNext;
        State *nextStates;
        bool   timeout;
    } StateData;
    
    void StateCreateInit(StateData **s, State st, int numnext, ...);
    
    int main() {
        int resp;
        StateData **states;
        StateData *curr;
    
        states = malloc(NumStates * sizeof(*states));
        for(int i = 0; i < NumStates; i++)
            states[i] = malloc(sizeof(*states[i]));
    
        StateCreateInit(states, State0, 2, State1, State2);
        StateCreateInit(states, State1, 1, State2);
        StateCreateInit(states, State2, 1, State0);
    
        curr = states[State0];
    
        while (true) {
            printf("Current State is %d. Next states: ", curr->state);
            for(int i = 0; i < curr->numNext; i++)
                printf("%d ", curr->nextStates[i]);
            printf("\nNext state: ");
    
            scanf("%d", &resp);
            if (resp == -1) break;
    
            for(int i = 0; i < curr->numNext; i++)
                if (curr->nextStates[i] == resp) {
                    curr = states[curr->nextStates[i]];
                    break;
                }
        }
        return 0;
    }
    
    void StateCreateInit(StateData **s, State st, int numnext, ...) {
        va_list va;
        va_start(va, numnext);
        s[st]->state = st;
        s[st]->numNext = numnext;
        s[st]->nextStates = malloc(s[st]->numNext * sizeof(*s[st]->nextStates));
        for (int i = 0; i < numnext; i++)
            s[st]->nextStates[i] = va_arg(va, int);
        s[st]->timeout = false;
        va_end(va);
    }
    What is the timeout flag for?
    How is this to be used in your actual program?
    Last edited by algorism; 03-05-2016 at 11:35 AM. Reason: typo (yikes!)

  6. #6
    Registered User
    Join Date
    Dec 2015
    Posts
    112
    Algorism,

    The timeout flag will be a timeout in ms. Some of the states ignore incoming messages for a period of time and then transition to another state.

    In my real example I will be storing the message type, compare it to the incoming message and then transition to the correct state. I would need some lookup table in between to just use the index, which be easier to follow.

    The va_arg seems to be a great way to cut down on the amount of code I have.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Finite state machine
    By wildanlsfs in forum C Programming
    Replies: 1
    Last Post: 11-16-2014, 10:05 PM
  2. FSM(Finite state machine) help
    By sed_y in forum C++ Programming
    Replies: 4
    Last Post: 11-07-2011, 04:40 PM
  3. Sequential State Machine
    By Blacky Ducky in forum C++ Programming
    Replies: 6
    Last Post: 07-16-2011, 09:44 PM
  4. State machine
    By sergio in forum General Discussions
    Replies: 3
    Last Post: 07-03-2009, 09:03 AM
  5. Designing State Machine
    By axon in forum Tech Board
    Replies: 3
    Last Post: 11-06-2003, 12:13 PM