Finite state machine (FSM) is a mathematical model to express the behavior of finite state and the transfer and movement between these states, which is widely used in computer field. Typically an FSM consists of several elements: state management, State monitoring, state triggering, and state-triggered actions. This paper mainly expounds several design methods of state machine.
1:switch case/if Else Design method
Curevent == getcurstate (); Switch (curstate) { case state1: { switch(curevent) { TODO ... Setcurstate (); Break ; } Break ; } ...}
This design method is the simplest, handled by a large stack of judgments, and is suitable for small-scale state-switching processes, but is difficult to scale and maintain if scaled.
2: Table-based state machine design method: Set up the corresponding state table and action query table, according to the state table, events, action table to locate the corresponding action processing function, after the completion of the implementation of the state switch.
A general-purpose state Machine processing module is designed as follows:
/*Status Table Registration*/voidFsm_regist (fsm_t* pfsm,state_table_s*pstatetable) {PFSM->fsmtable =pstatetable; return;}/*State Migration*/voidFsm_movestate (fsm_t* PFSM,intState ) {PFSM->curstate =State ; return;}/*Event Handling*/voidFsm_eventhandle (fsm_t* PFSM,int Event) {act_table_t* Pacttable =NULL; Actfun Eventactfun=NULL; /*get the current Status action table*/pacttable=fsm_getacttable (PFSM); /*get current action function*/ for(intI=0; i<max_act_num;i++) { if(Event= = Pacttable[i].Event) {Eventactfun=Pacttable[i].eventactfun; Break; } } /*Action Execution*/ if(Eventactfun) {eventactfun (PFSM); }}
Suppose our state diagram is as follows:
The corresponding state machine settings are as follows:
/*action table for status 1*/act_table_t state1acttable[]={{Event1,state1event1fun}, {event3,state1event3fun},};/*action table for status 2*/act_table_t state2acttable[]={{event2,state2event2fun},};/*Status Table*/state_table_t fsmtable[]={{state1,state1acttable}, {state2,state2acttable},};intMainintARGC, _tchar*argv[]) {fsm_t FSM; /*Status Table Registration*/Fsm_regist (&fsm,fsmtable); Fsm_movestate (&fsm,state1); Fsm_eventhandle (&fsm,event1); Fsm_eventhandle (&Fsm,event2); return 0;}/*state handling functions provided by the client*/voidState1event1fun (void*PFSM) {Fsm_movestate (fsm_t*) pfsm,state2); return;}voidState1event3fun (void*PFSM) {Fsm_movestate (fsm_t*) pfsm,state3); return;}voidState2event2fun (void*PFSM) {Fsm_movestate (fsm_t*) pfsm,state3); return;}
By designing a common table-based state machine module, for different state graphs, we only need to get its state table structure according to the state graph, and then register with Fsm_regist, we can use the function of state machine conveniently. This mechanism is convenient for us to add new state flow, and it can be well designed for layered state machine.
Design of a layered state machine:
For state machines with more states, the usual design maintains a large two-dimensional matrix, all of which are coupled together, often resulting in maintenance difficulties, because there may be many common features that can cause many States to have the same handler function. We can solve these problems by designing the layered state machine, the main idea is to design a plurality of state machines according to different function modules, each state machine is distributed at different levels. When the upper state machine is called, the upper state machine is in the stack, and the lower state machine becomes the current processing state machine. Usually we use stacks to hold the top state machine information for the current state machine.
Describes a layered state machine design implementation:
As shown, assuming that the L1 is an upper state machine, the L1 state machine can be triggered into the L2 state machine in L1_state2 by L1l2_event1 event, and L2 state machine is triggered by L2_state2 event in L1l2_event2 to return to the L1 state machine, L1 and L2 each maintain their own state tables.
structfsm_s{intCurstate;//Current state machine status intCurfsmtablesize;//Current state machine query table sizestate_table_t* curfsmtable;//Current state machine query tablefsm_stack_t STACK[MAX_FSM_STACK_DEP];//state Machine Stack intCurstacktop;//Top of Stackfsm_regist_t Registfsm[max_fsm_num];//Register State Machine intRegistfsmnum;//number of registered state machines};
1: Maintain upper state machine information through stack data structure.
2: Save all the state machine information that can be registered.
3: Records the current running state machine information.
Main interface:
void Fsm_init (fsm_t* PFSM); void Fsm_regist (fsm_t* pfsm,state_table_s* pstatetable,int fsmid,int curfsmtablesize); void Fsm_begin (fsm_t* pfsm,int fsmid); void Fsm_movestate (fsm_t* pfsm,int state ); void Fsm_eventhandle (fsm_t* pfsm,intevent); void Fsm_push (fsm_t* PFSM); void Fsm_pop (fsm_t* PFSM);
1:fsm_regist Registration of all state machine information
void Fsm_regist (fsm_t* pfsm,state_table_s* pstatetable,intint curfsmtablesize) { PFSM- >registfsm[pfsm->registfsmnum].fsmid = Fsmid; PFSM->registfsm[pfsm->registfsmnum]. fsmtable = pstatetable; PFSM->registfsm[pfsm->registfsmnum].fsmtablesize = curfsmtablesize; PFSM->registfsmnum++; return ;}
The 2:fsm_begin is used to start a new state machine process and toggle the state table information.
void Fsm_begin (fsm_t* pfsm,int fsmid) { for (int i=0;i<pfsm-> registfsmnum;i++) { if(fsmid = = pfsm->registfsm[i].fsmid) { PFSM ->curfsmtable = pfsm->registfsm[i]. fsmtable; PFSM->curfsmtablesize = pfsm->registfsm[i].fsmtablesize; Break ; } } return ;}
The 3:fsm_push/fsm_pop is used for state machine switching of the access stack operation.
voidFsm_push (fsm_t*PFSM) { if(Pfsm->curstacktop <MAX_FSM_STACK_DEP) {PFSM->curstacktop++; PFSM->stack[pfsm->curstacktop].state = pfsm->curstate; PFSM->stack[pfsm->curstacktop].pfsmtable = pfsm->curfsmtable; PFSM->stack[pfsm->curstacktop].fsmtablesize = pfsm->curfsmtablesize; } return;}voidFsm_pop (fsm_t*PFSM) { if(Pfsm->curstacktop >-1) {PFSM->curstate = pfsm->stack[pfsm->curstacktop].state; PFSM->curfsmtable = pfsm->stack[pfsm->curstacktop].pfsmtable; PFSM->curfsmtablesize = pfsm->stack[pfsm->curstacktop].fsmtablesize; PFSM->curstacktop--; } return;}
Use of the interface:
/*L1 state Machine definition*/act_table_t l1state1acttable[]={{L1_event1,l1state1_event1fun}, {l1_event3,l1state1_event3fun},}; act_table_t l1state2acttable[]={{L1_event2,l1state2_event2fun}, {l1_l2_event1,l1state2_l1l2eventfun},}; state_table_t l1fsmtable[]={{l1_state1,sizeof(l1state1acttable)/sizeof(act_table_t), l1state1acttable}, {l1_state2,sizeof(l1state2acttable)/sizeof(act_table_t), l1state2acttable},};/*L2 state Machine definition*/act_table_t l2state1acttable[]={{l2_event1,l2state1_l2event1fun},}; act_table_t l2state2acttable[]={{l1_l2_event2,l2state2_l1l2evenfun},}; state_table_t l2fsmtable[]={{l2_state1,sizeof(l2state1acttable)/sizeof(act_table_t), l2state1acttable}, {l2_state2,sizeof(l2state2acttable)/sizeof(act_table_t), l2state2acttable},};intMainintARGC, _tchar*argv[]) {fsm_t PFSM; Fsm_init (&PFSM); /*State Machine Registration*/Fsm_regist (&PFSM,L1FSMTABLE,FSM_L1,sizeof(l1fsmtable)/sizeof(state_table_t)); Fsm_regist (&PFSM,L2FSMTABLE,FSM_L2,sizeof(l2fsmtable)/sizeof(state_table_t)); /*start L1 State machine*/Fsm_begin (&pfsm,fsm_l1); Fsm_movestate (&pfsm,l1_state1); Fsm_eventhandle (&pfsm,l1_event1); /*Push State machine*/Fsm_eventhandle (&pfsm,l1_l2_event1); /*L2 state Machine processing*/Fsm_eventhandle (&pfsm,l2_event1); /*Pop State Machine*/Fsm_eventhandle (&Pfsm,l1_l2_event2); /*L1 state Machine processing*/Fsm_eventhandle (&Pfsm,l1_event2); return 0;}
1: First register all state machines via fsm_regist.
2:fsm_eventhandle (&Pfsm,l1_l2_event1) in the action processing function in the press stack operation at the same time into the L2 state machine.
void L1state2_l1l2eventfun (void* pfsm) { Fsm_push ((fsm_t*) PFSM); Fsm_begin ((fsm_t*) pfsm,fsm_l2); Fsm_movestate ((fsm_t*) pfsm,l2_state1); return ;}
3:fsm_eventhandle (&Pfsm,l1_l2_event2) in the action handler function is returned to the L1 state machine in the stack operation.
void L2state2_l1l2evenfun (void* pfsm) { Fsm_pop ((fsm_t*) PFSM); return ;}
Conclusion:
Through the design of layered state machine, each functional entity maintains its own strong correlative set of state machine, which can reduce the complexity of state machine effectively, and can reduce the scale by constructing the public process state machine. In summary: In the design of state machine with large scale and complicated process, we consider using layered design method.
Reprint please indicate original source: http://www.cnblogs.com/chencheng/archive/2012/06/28/2564336.html
Design and implementation of finite state machine (FSM)