http://blog.ankurs.com/2010/04/simple-finite-state-machines-in-c/
Simple Finite State Machines in C
I was having discussion about State Machines with one of my friend, regarding pro’s and con’s of implementing programs as Sate Machines, it was then that i realised there is no simple way to implement programs as Finite State Machines, so here is a very basic implementation of FSM in C github repo
file: fsm.h contains the function definition for our FSM
| /** | |
| * @file fsm.h | |
| * @brief an implementation for a FSM in C, this file contains | |
| * all definations required for FSM. | |
| * License GPLv3+ | |
| * @author Ankur Shrivastava | |
| */ | |
| // forword decleration | |
| struct fsm_object; | |
| /** | |
| * @struct fsm_state fsm.h "fsm.h" | |
| * @brief Stores information regarding state | |
| */ | |
| struct fsm_state{ | |
| /** | |
| * Stores the name of the state | |
| */ | |
| char *name; | |
| /** | |
| * stores the function pointer for the state | |
| */ | |
| void (*function)(struct fsm_object* ,int,void**); | |
| /** | |
| * pointer to the next state | |
| */ | |
| struct fsm_state *next; | |
| }; | |
| /** | |
| * @struct fsm_object fsm.h "fsm.h" | |
| * @brief stores info regarding state machine | |
| */ | |
| struct fsm_object{ | |
| /** | |
| * pointer to the linked list of fsm_state structures | |
| */ | |
| struct fsm_state * fsm_base; | |
| /** | |
| * name of current FSM state | |
| */ | |
| struct fsm_state * fsm_cur_state; | |
| /** | |
| * number of argument passed to the nest state | |
| */ | |
| char * fsm_cur_state_name; | |
| /** | |
| * pointer to current FSM state | |
| */ | |
| int fsm_arg_num; | |
| /** | |
| * values of arguments passed to the next state | |
| */ | |
| void ** fsm_arg_value; | |
| }; | |
| /** | |
| * Function to initialize the FSM | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| */ | |
| int fsm_init(struct fsm_object *obj); | |
| /** | |
| * The FSM entry point, this is where execution of code begins in FSM. | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| */ | |
| int fsm_main(struct fsm_object *obj); | |
| /** | |
| * Execution of next state takes place here | |
| * @details function fsm_next can be used without fsm_main when we want to hadel | |
| * state execution and not rely on fsm_main 's loop | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| */ | |
| int fsm_next_state(struct fsm_object *obj); | |
| /** | |
| * Function to add a new state to the FSM. | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| * @param state name of the state to be added. | |
| * @param fun name of the function to be executed for this state | |
| */ | |
| int fsm_add(struct fsm_object *obj, char *state, void (*fun)(struct fsm_object *, int, void **) ); | |
| /** | |
| * Function to add a default state to FSM. | |
| * @details Adds a default state to FSM, this is the function called at the start of the FSM | |
| * or in case of error, with the appropriate error code | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| * @param fun name of the function to be executed for this state | |
| */ | |
| int fsm_default(struct fsm_object *obj, void (*fun)(struct fsm_object *, int, void **) ); | |
| /** | |
| * Function to remove a state from the FSM. | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| * @param state name of state to be removed | |
| */ | |
| int fsm_remove(struct fsm_object *obj, char *state); | |
| /** | |
| * Function to change state. | |
| * @details changes state to the new specified state, if the state does not exist returns error, | |
| * state change is not triggered till function calling fsm_to_state returns | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| * @param state name of state to chnage to | |
| * @param num number of arguments | |
| * @param arg arguments | |
| */ | |
| int fsm_to_state(struct fsm_object *obj, char *state, int num, void** arg); | |
| /** | |
| * Function for FSM termination | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| */ | |
| void fsm_terminate(struct fsm_object *obj); |
file: fsm.c contains the function implementation for our FSM
| /** | |
| * @file fsm.c | |
| * @brief an implementation for a FSM in C, this file contains | |
| * implementation of definations. | |
| * License GPLv3+ | |
| * @author Ankur Shrivastava | |
| */ | |
| #include "fsm.h" | |
| #include<stdlib.h> | |
| #include<string.h> | |
| /** | |
| * Function to initialize the FSM | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| */ | |
| int fsm_init(struct fsm_object *obj) | |
| { | |
| //initialize everything to Null or 0 | |
| obj->fsm_base = NULL; | |
| obj->fsm_cur_state_name = NULL; | |
| obj->fsm_arg_num = 0; | |
| obj->fsm_arg_value = NULL; | |
| return 0; | |
| } | |
| /** | |
| * Execution of next state takes place here | |
| * @details function fsm_next can be used without fsm_main when we want to hadel | |
| * state execution and not rely on fsm_main 's loop | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| */ | |
| int fsm_next_state(struct fsm_object *obj) | |
| { | |
| struct fsm_state *tmp = obj->fsm_base; | |
| if ((obj->fsm_base==NULL)||(obj->fsm_cur_state_name==NULL)) | |
| { | |
| return -1; | |
| } | |
| while ((tmp->name != obj->fsm_cur_state_name)&&(tmp!=NULL)) | |
| tmp = tmp->next; | |
| if (tmp == NULL) | |
| return -1; | |
| tmp->function(obj,obj->fsm_arg_num,obj->fsm_arg_value); | |
| return 0; | |
| } | |
| /** | |
| * The FSM entry point, this is where execution of code begins in FSM. | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| */ | |
| int fsm_main(struct fsm_object *obj) | |
| { | |
| while (!fsm_next_state(obj)); | |
| return 0; | |
| } | |
| /** | |
| * Function to add a new state to the FSM. | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| * @param state name of the state to be added. | |
| * @param fun name of the function to be executed for this state | |
| */ | |
| int fsm_add(struct fsm_object *obj, char *state, void (*fun)(struct fsm_object *, int ,void **) ) | |
| { | |
| struct fsm_state *tmp = obj->fsm_base; | |
| struct fsm_state *new_state = malloc(sizeof(struct fsm_state)); | |
| while(tmp->next) | |
| tmp = tmp->next; | |
| new_state->name = state; | |
| new_state->function = fun; | |
| new_state->next=NULL; | |
| tmp->next=new_state; | |
| return 0; | |
| } | |
| /** | |
| * Function to remove a state from the FSM. | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| * @param state name of state to be removed | |
| */ | |
| int fsm_remove(struct fsm_object *obj,char *state) | |
| { | |
| if (!strcmp(state,"default")) | |
| return -1; | |
| struct fsm_state *to_del; | |
| struct fsm_state *tmp=obj->fsm_base; | |
| while((tmp->next!=NULL)&&(strcmp(tmp->next->name,state))) | |
| tmp=tmp->next; | |
| if (tmp == NULL) | |
| return -1; | |
| to_del = tmp->next; | |
| tmp->next = tmp->next->next; | |
| free(to_del); | |
| return 0; | |
| } | |
| /** | |
| * Function to change state. | |
| * @details changes state to the new specified state, if the state does not exist returns error, | |
| * state change is not triggered till function calling fsm_to_state returns | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| * @param state name of state to chnage to | |
| * @param num number of arguments | |
| * @param arg arguments | |
| */ | |
| int fsm_to_state(struct fsm_object *obj, char *state, int num, void** arg) | |
| { | |
| struct fsm_state *tmp=obj->fsm_base; | |
| while((tmp!=NULL)&&(strcmp(tmp->name,state))) | |
| tmp=tmp->next; | |
| if (tmp == NULL) | |
| return -1; | |
| obj->fsm_cur_state = tmp; | |
| obj->fsm_cur_state_name = tmp->name; | |
| obj->fsm_arg_num = num; | |
| obj->fsm_arg_value=arg; | |
| return 0; | |
| } | |
| /** | |
| * Function to add a default state to FSM. | |
| * @details Adds a default state to FSM, this is the function called at the start of the FSM | |
| * or in case of error, with the appropriate error code | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| * @param fun name of the function to be executed for this state | |
| */ | |
| int fsm_default(struct fsm_object *obj, void (*fun)(struct fsm_object *, int ,void **) ) | |
| { | |
| obj->fsm_base = malloc(sizeof(struct fsm_state)); | |
| obj->fsm_base->name="default"; | |
| obj->fsm_base->function = fun; | |
| obj->fsm_base->next = NULL; | |
| // set current state to default | |
| obj->fsm_cur_state = obj->fsm_base; | |
| obj->fsm_cur_state_name = obj->fsm_base->name; | |
| return 0; | |
| } | |
| /** | |
| * Function for FSM termination | |
| * @param obj pointer to structure of type fsm_object, which defines the FSM | |
| */ | |
| void fsm_terminate(struct fsm_object *obj) | |
| { | |
| // delete all states to prevent memory leek | |
| struct fsm_state *tmp = obj->fsm_base; | |
| struct fsm_state *to_del=tmp; | |
| while(tmp) | |
| { | |
| to_del = tmp; | |
| tmp=tmp->next; | |
| free(to_del); | |
| } | |
| // reset FSM base to NULL causes while loop in fsm_main to quit | |
| // terminating the program | |
| obj->fsm_cur_state = NULL; | |
| obj->fsm_cur_state_name = NULL; | |
| obj->fsm_base = NULL; | |
| } |
file: main.c contains an example on how this FSM can be used
| // Program to test FSM | |
| // License GPLv3+ | |
| #include "fsm.h" | |
| #include<stdio.h> | |
| void abc(struct fsm_object *obj, int val,void **arg) | |
| { | |
| // state -> default | |
| printf("%d\n",val); | |
| printf("%s\n",obj->fsm_cur_state_name); | |
| fsm_to_state(obj,"hello",0,NULL); | |
| } | |
| void pqr(struct fsm_object *obj, int val,void **arg) | |
| { | |
| // state -> qwerty | |
| printf("%d\n",val); | |
| printf("%s\n",obj->fsm_cur_state_name); | |
| fsm_to_state(obj,"default",0,NULL); | |
| } | |
| void xyz(struct fsm_object *obj, int val,void **arg) | |
| { | |
| // state -> hello | |
| printf("%d\n",val); | |
| printf("%s\n",obj->fsm_cur_state_name); | |
| // fsm_terminate(obj); | |
| fsm_to_state(obj,"qwerty",0,NULL); | |
| } | |
| int main() | |
| { | |
| // create FSM object | |
| struct fsm_object obj; | |
| // initialize it | |
| fsm_init(&obj); | |
| // set default function | |
| fsm_default(&obj,abc); | |
| // add moe states | |
| fsm_add(&obj,"qwerty",pqr); | |
| fsm_add(&obj,"hello",xyz); | |
| // start the main FSM loop | |
| fsm_main(&obj); | |
| return 0; | |
| } |
No hay comentarios:
Publicar un comentario