"State Machine Shortcuts" Michael Kreiman Embedded Systems Programming July 2003 /***************************************************** Figure #1 Code ******************************************************/ typedef unsigned char unsigned8; typedef enum { NULL_EVENT = 0, EV_1, EV_2, EV_3, EV_4, EV_5, EV_6, EV_7, EV_8, EV_9 } event_type; typedef void (*functionPointerType)(void); #define NUM_MODES 2 #define NO_NEW_STATE 0 #define ANY_STATE 1 #define SUPER_STATE_A 2 #define STATE_B 3 /* Substates */ #define SUB_STATE_A 0 #define SUB_STATE_B 1 #define SUB_STATE_C 2 #define SUB_STATE_D 3 typedef struct state_table_type { unsigned8 current_state; event_type received_event; functionPointerType execute_function; unsigned8 next_state; unsigned8 next_mode; }; static unsigned8 current_mode; static unsigned8 current_state; void null_function(void); void Conditional_1(void); void Guard_1(void); void Entry_Action_B_C(void); void Transition_Action_B(void); void Entry_Action_A(void); void Transition_Action_C(void); void Entry_Action_D(void); void Null_function(void); void Transition_Action_A(void); const struct state_table_type SUPER_STATE_A_STATE_TABLE[] = { { SUB_STATE_A, EV_1, Conditional_1, NO_NEW_STATE, SUPER_STATE_A }, { SUB_STATE_B, EV_2, Guard_1, NO_NEW_STATE, SUPER_STATE_A }, { ANY_STATE, EV_4, Entry_Action_B_C, SUB_STATE_C, SUPER_STATE_A }, { SUB_STATE_C, EV_3, Transition_Action_B, SUB_STATE_D, SUPER_STATE_A }, { SUB_STATE_D, EV_5, Entry_Action_A, NO_NEW_STATE, SUPER_STATE_A }, { ANY_STATE, EV_7, Null_function, NO_NEW_STATE, STATE_B }, { SUB_STATE_D, EV_5, Transition_Action_C, NO_NEW_STATE, SUPER_STATE_A } }; const struct state_table_type STATE_B_STATE_TABLE[] = { { ANY_STATE, EV_8, Entry_Action_D, SUB_STATE_D, SUPER_STATE_A }, { ANY_STATE, EV_9, Entry_Action_A, SUB_STATE_A, SUPER_STATE_A } }; const struct state_table_type * MODE_TABLE[2] = { & SUPER_STATE_A_STATE_TABLE [0], &STATE_B_STATE_TABLE[0], }; const unsigned8 STATE_TABLE_SIZE[NUM_MODES] = { 9, 2, }; /* Event receptor function */ void class_receive_event( event_type event ) { unsigned8 i; const struct state_table_type * thisTable = MODE_TABLE[current_mode]; /* Note: This generic table processor function can be pulled out and reused as a utility for many state machines, thus reusing the code */ for ( i = 0; i < STATE_TABLE_SIZE[current_mode]; i++ ) { if ( ( event == thisTable->received_event ) && ( ( current_state == thisTable->current_state ) || ( thisTable->current_state == ANY_STATE ) ) ) { (*thisTable->execute_function)(); if ( thisTable->next_state != NO_NEW_STATE ) { current_state = thisTable->next_state; } current_mode = thisTable->next_mode; break; } thisTable++; } } void null_function(void) { } void Conditional_1(void) { if ( case_X ) { current_state = SUB_STATE_B; /* Flesh out execute actions here */ } else if ( case_Y ) { current_state = SUB_STATE_C; Transition_Action_A(); Entry_Action_B_C(); } } void Guard_1(void) { if ( case_Z ) { current_state = SUB_STATE_C; Entry_Action_B_C(); } } void Entry_Action_B_C(void) { /* Flesh out execute actions here */ } void Transition_Action_A(void) { /* Flesh out execute actions here */ } void Transition_Action_B(void) { /* Flesh out execute actions here */ } void Entry_Action_A(void) { /* Flesh out execute actions here */ } void Transition_Action_C(void) { /* Flesh out execute actions here */ } void Entry_Action_D(void) { /* Flesh out execute actions here */ }