我將A pattern for state machine改寫成framework形式,使用者需要先使用sm_alloc()分配一個struct sm,再使用sm_fp_reg()將每個state的callback function掛上,最後有event要執行時,只要呼叫sm_run(sm, new_event)即可。
state的callback function的撰寫邏輯,大致與之前一樣,return下一個state,進入下一個state要做的動作,我都用do_state_x()包起來,而do_state_x()會return 該state。
sm.h
#ifndef SM_H #define SM_H struct sm { int cur_state; int prv_event; void *v; }; /** * state function * @return next state */ typedef int (*sm_st_fp)(struct sm *sm, int new_event); struct sm *sm_alloc(int num_of_state); int sm_run(struct sm *s, int new_event); int sm_fp_reg(struct sm *s, int state, sm_st_fp fp); #endif
sm.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "sm.h" struct _sm { struct sm s; int num_of_st; sm_st_fp fp[0]; }; struct sm *sm_alloc(int num_of_state) { struct _sm *_s; int sz; sz = sizeof(struct _sm) + sizeof(sm_st_fp) * num_of_state; _s = (struct _sm*) malloc(sz); if (!_s) { return NULL; } memset(_s, 0, sz); _s->num_of_st = num_of_state; return (struct sm*)_s; } int sm_run(struct sm *s, int new_event) { struct _sm *_s = (struct _sm*) s; if (s->cur_state > _s->num_of_st) { printf("out of st\n"); return -1; } if (!_s->fp[s->cur_state]) { printf("null fp\n"); return -1; } s->cur_state = _s->fp[s->cur_state](s, new_event); s->prv_event = new_event; return 0; } int sm_fp_reg(struct sm *s, int state, sm_st_fp fp) { struct _sm *_s = (struct _sm*) s; if (state > _s->num_of_st) { printf("out of st\n"); return -1; } _s->fp[state] = fp; return 0; }
main.c
因為是framework,所以,我把state/event都拉出來, 因此每個State Machine都應該定義自己的event與state。 enum state { STATE_1, STATE_2, STATE_3, STATE_4, }; enum event { E1 = 1, E2, E3, E4, }; int main(int argc, char *argv[]) { struct sm *s; char ch; s = sm_alloc(3); if (!s) { return -1; } sm_fp_reg(s, STATE_1, in_state_1); sm_fp_reg(s, STATE_2, in_state_2); sm_fp_reg(s, STATE_3, in_state_3); sm_fp_reg(s, STATE_4, in_state_4); while (1) { while (((ch = getc(stdin)) == '\n') || (ch < '0') || (ch > '4')); sm_run(s, ch - '0'); } return 0; }
refine callback function
因為是framework,所以,callback function的定義要改成return int。 int do_s1(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_1; } int do_s2(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_2; } int do_s3(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_3; } int do_s4(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_4; } int in_state_1(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E1: printf("change to S2\n"); return do_s2(); case E2: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do nothing\n"); return STATE_1; } } int in_state_2(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E3: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do s2 again\n"); return do_s2(); // do s2 again } } int in_state_3(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E2: printf("change to S4\n"); return do_s4(); default: printf("keep the same STATE && do nothing\n"); return STATE_3; } } int in_state_4(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E1: printf("change to S2\n"); return do_s2(); case E3: printf("change to S1\n"); return do_s1(); default: printf("keep the same STATE && do again\n"); return do_s4(); } }