martes, 10 de mayo de 2022

Simple Finite State Machines in C

 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);
view rawfsm.h hosted with ❤ by GitHub

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;
}
view rawfsm.c hosted with ❤ by GitHub

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