This is a little C program used to show the framework of state machine programming (smp,状态机编程). Detailed state transition picture is as below. Try to build the source code below and enjoy:)
/*
* State Machine Program (SMP)
* This program is used to construct basic framework
* of state machine programming, which is very useful
* in telecom software. Imagine when a protocol stack,
* multi-threads and socket are involved here…
* Language: C/C++
* OS: Unix/Linux
* Originated: Dec 29, 2010
* dave.tian@alcatel-lucent.com
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MSG_BUF_SIZE_MAX 1000
/* Event definition used to tigger State transition */
typedef enum _QuestionEvent
{
QUESTION_NONE,
QUESTION_HI,
QUESTION_WHO_ARE_YOU,
QUESTION_BYE,
QUESTION_NOT_SUPPORTED,
QUESTION_MAX
} QuestionEvent;
/* State definition */
typedef enum _ProgramMoodState
{
PROGRAM_MOOD_STATE_NONE,
PROGRAM_MOOD_STATE_GOOD,
PROGRAM_MOOD_STATE_HIGH,
PROGRAM_MOOD_STATE_ANY,
PROGRAM_MOOD_STATE_MAX
} ProgramMoodState;
/* Function definition for State transition */
typedef void (*ProgramActionFunction) (void);
/* State Machine transition element definition */
typedef struct _ProgramStateMachineTransition
{
ProgramMoodState currentState;
QuestionEvent eventReceived;
ProgramActionFunction actionFunction;
ProgramMoodState newState;
} ProgramStateMachineTransition;
/* State Machine entry definition used during transition */
typedef struct _ProgramStateMachineEntry
{
ProgramActionFunction actionFunction;
ProgramMoodState newState;
} ProgramStateMachineEntry;
/* Action function declaration for different state transition
* ‘static’ is used here to guarantee that the function could
* only be used within this source file */
static void processOthers( void);
static void processWhoAreYouBeforeHi( void);
static void processByeBeforeHi( void);
static void processHiAfterHi( void);
static void processByeAfterHi( void);
static void processHiAfterWhoAreYou( void);
static void processWhoAreYouAfterWhoAreYou( void);
static void processHi( void);
static void processWhoAreYou( void);
static void processBye( void);
/* State Machine transition table definition
* ‘static’ is used here to guarantee that only
* functions in this source file could access this table */
static ProgramStateMachineTransition programSMTtable[] =
{
/* This is the core part of State Machine Programming */
/* Unexpected state transition handling below */
{PROGRAM_MOOD_STATE_ANY, QUESTION_NOT_SUPPORTED, processOthers, PROGRAM_MOOD_STATE_NONE},
{PROGRAM_MOOD_STATE_NONE, QUESTION_WHO_ARE_YOU, processWhoAreYouBeforeHi, PROGRAM_MOOD_STATE_NONE},
{PROGRAM_MOOD_STATE_NONE, QUESTION_BYE, processByeBeforeHi, PROGRAM_MOOD_STATE_NONE},
{PROGRAM_MOOD_STATE_GOOD, QUESTION_HI, processHiAfterHi, PROGRAM_MOOD_STATE_GOOD},
{PROGRAM_MOOD_STATE_GOOD, QUESTION_BYE, processByeAfterHi, PROGRAM_MOOD_STATE_NONE},
{PROGRAM_MOOD_STATE_HIGH, QUESTION_HI, processHiAfterWhoAreYou, PROGRAM_MOOD_STATE_HIGH},
{PROGRAM_MOOD_STATE_HIGH, QUESTION_WHO_ARE_YOU, processWhoAreYouAfterWhoAreYou, PROGRAM_MOOD_STATE_HIGH},
/* Expected state transition handling below */
{PROGRAM_MOOD_STATE_NONE, QUESTION_HI, processHi, PROGRAM_MOOD_STATE_GOOD},
{PROGRAM_MOOD_STATE_GOOD, QUESTION_WHO_ARE_YOU, processWhoAreYou, PROGRAM_MOOD_STATE_HIGH},
{PROGRAM_MOOD_STATE_HIGH, QUESTION_BYE, processBye, PROGRAM_MOOD_STATE_NONE}
};
/* Max number of entries definition used to State Machine initialization
* for SMP, this value is used to determine how many entries init’ed from
* programSMTtable[] to programSMTentry[][]. This value should not bigger
* than the max size of array programSMTtable. Once programSMTtable[] is
* added new state transitions, this value needs to be updated */
#define STATE_MACHINE_ENTRY_MAX 10
/* State Machine transition entry definition
* used to provide usable entry to State Machine
* transition table – init’ed by transition table */
static ProgramStateMachineEntry programSMTentry[ PROGRAM_MOOD_STATE_MAX][ QUESTION_MAX];
int main ( void)
{
/* Globle variable standing for this program’s mood */
ProgramMoodState myMood = PROGRAM_MOOD_STATE_NONE;
/* Globel variable standing for event got from user */
QuestionEvent myEvent = QUESTION_NONE;
char msgBuf[ MSG_BUF_SIZE_MAX];
char *stringPtr;
int i;
printf(“nState Machine Program (SMP)n”);
printf(“Developed by Stupid Maniac Programmer (SMP) davetin”);
printf(“dave.tian@alcatel-lucent.comn”);
printf(“Type ‘help’ for detailed usagen”);
/* Init State Machine (entry) */
initSMT();
while ( 1)
{
myEvent = QUESTION_NONE;
printf(“n>> “);
/*
* scanf() is unable to support empty input – stupid
* gets() is able to cause buffer overflow – dangerous
* fgets() is including the newline right before ” – no comment
*/
/* Note: newline is read into buffer 2! */
fgets( msgBuf, MSG_BUF_SIZE_MAX, stdin);
/* Change the newline to null */
msgBuf[ strlen( msgBuf) – 1] = ”;
stringPtr = msgBuf;
for ( i = 0; i < strlen( msgBuf); i++)
{
if ( isspace( msgBuf[ i]))
{
/* Bypass the whitespaces forwarded */
stringPtr++;
}
else
{
break;
}
}
if ( stringPtr == msgBuf + strlen( msgBuf))
{
/* No valid input in this time */
continue;
}
if ( strcasecmp( stringPtr, “hi”) == 0)
{
myEvent = QUESTION_HI;
}
else if ( strcasecmp( stringPtr, “whoru”) == 0)
{
myEvent = QUESTION_WHO_ARE_YOU;
}
else if ( strcasecmp( stringPtr, “bye”) == 0)
{
myEvent = QUESTION_BYE;
}
else if ( strcasecmp( stringPtr, “help”) == 0)
{
showHelp();
continue;
}
else if (strcasecmp( stringPtr, “exit”) == 0)
{
/* Exit SMP */
return 0;
}
else
{
myEvent = QUESTION_NOT_SUPPORTED;
}
/* Start State Machine Transition */
startSMT( &myMood, myEvent);
}
return 0;
}
/* State Machine (entry) initialization function definition */
void initSMT( void)
{
QuestionEvent e;
ProgramMoodState s, sNew;
ProgramActionFunction af;
int i;
for ( i = 0; i < STATE_MACHINE_ENTRY_MAX; i++)
{
s = programSMTtable[ i].currentState;
e = programSMTtable[ i].eventReceived;
af = programSMTtable[ i].actionFunction;
sNew = programSMTtable[ i].newState;
programSMTentry[ s][ e].actionFunction = af;
programSMTentry[ s][ e].newState = sNew;
}
}
/* State Machine transition function definition */
void startSMT( ProgramMoodState *myMood, QuestionEvent event)
{
ProgramMoodState mState;
ProgramStateMachineEntry *smEntry;
if ( event == QUESTION_NOT_SUPPORTED)
{
/* Update the local mood state to wildcard */
mState = PROGRAM_MOOD_STATE_ANY;
}
else
{
/* Set the local mood state to globle mood */
mState = *myMood;
}
/* Do the mapping via programSMTtable */
smEntry = &programSMTentry[ mState][ event];
/* Note: no pointer checking here – memory fault may happen if
* un-covered state transition in state machine transition table
* is triggered here – be ware of this! */
/* Call for action function */
smEntry->actionFunction();
/* Update the globle mood with new state */
*myMood = smEntry->newState;
}
/* Detailed action function definitions */
void processWhoAreYouBeforeHi( void)
{
printf(“Hey, Man, u never say hi to me before asking who i am…n”);
}
void processByeBeforeHi( void)
{
printf(“Hey, Man, u never say hi before saying bye to me…ok, bye…n”);
}
void processHiAfterHi( void)
{
printf(“Hey, Man, I am sure this is not the first time u saying hi to me…r u a hi machine?n”);
}
void processByeAfterHi( void)
{
printf(“Bye, Man!n”);
}
void processHiAfterWhoAreYou( void)
{
printf(“Hey, Man, u are saying hi to me againe…ok, hi…n”);
}
void processWhoAreYouAfterWhoAreYou( void)
{
printf(“Hey, Man, u did ask me this question before right? I am SMP, us 2?n”);
}
void processOthers( void)
{
printf(“Hey, Man, couldn’t you please make me feel a little better?n”);
}
void processHi( void)
{
printf(“Hi, Man, you are so nice!n”);
}
void processWhoAreYou( void)
{
printf(“As you might have already known, I am a stupid State Machine Program coded by a nuts job…n”);
}
void processBye( void)
{
printf(“Bye, Man, wish you a good day!n”);
}
/* Stupid Boring help function definition */
void showHelp( void)
{
char dispBuf[ MSG_BUF_SIZE_MAX];
snprintf( dispBuf, MSG_BUF_SIZE_MAX, “%s”,
“SMP supports following questions/commands belown”
“hi – say hello to SMPn”
“whoru – ask SMP ‘who are you’n”
“bye – say byebye to SMPn”
“help – show this help menun”
“exit – exit SMPn”
“Note: any other words to SMP would make her feel unhappy!n” );
printf(“%s”, dispBuf);
}