181 lines
5.5 KiB
C
181 lines
5.5 KiB
C
#ifndef INCLUDED_GAI_FSM_H
|
|
#define INCLUDED_GAI_FSM_H
|
|
|
|
#ifndef INCLUDED_OS_TYPES_H
|
|
#include <os_types.h>
|
|
#endif /*INCLUDED_OS_TYPES_H*/
|
|
|
|
#ifndef INCLUDED_OS_COMPILER_H
|
|
#include <os_compiler.h>
|
|
#endif /*INCLUDED_OS_COMPILER_H*/
|
|
|
|
#ifndef INCLUDED_OS_LIST_H
|
|
#include <os_list.h>
|
|
#endif /*INCLUDED_OS_LIST_H*/
|
|
|
|
#ifndef INCLUDED_GAI_ACTION_H
|
|
#include <gai_action.h>
|
|
#endif /*INCLUDED_GAI_ACTION_H*/
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
|
/* */
|
|
|
|
typedef struct gai_fsm_state_t gai_fsm_state_t;
|
|
typedef struct gai_fsm_transition_t gai_fsm_transition_t;
|
|
typedef struct gai_fsm_t gai_fsm_t;
|
|
|
|
typedef os_bool_t (*gai_fsm_evaluator_t)(gai_fsm_t* self, gai_fsm_transition_t* transition, void* ud);
|
|
|
|
struct gai_fsm_state_t{
|
|
os_list_node_t node;
|
|
os_int_t id;
|
|
os_list_t transition_list;
|
|
gai_action_t action;
|
|
};
|
|
|
|
struct gai_fsm_transition_t{
|
|
os_list_node_t node;
|
|
os_int_t from_state_id;
|
|
os_int_t to_state_id;
|
|
gai_fsm_evaluator_t evaluator;
|
|
void* userdata;
|
|
};
|
|
|
|
struct gai_fsm_t{
|
|
gai_fsm_state_t* current_state_p;
|
|
os_list_t state_list;
|
|
void* userdata;
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
|
/* */
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
void gai_fsm_init(gai_fsm_t* self, void* userdata){
|
|
self->current_state_p = 0;
|
|
os_list_init(&self->state_list);
|
|
self->userdata = userdata;
|
|
}
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
void gai_fsm_add_state(gai_fsm_t* self, gai_fsm_state_t * state){
|
|
os_list_insert_after(&self->state_list, &state->node);
|
|
}
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
void gai_fsm_add_transition(gai_fsm_t* self, gai_fsm_transition_t* transition){
|
|
os_list_node_t* p_node;
|
|
for(p_node = self->state_list.next; p_node!=&self->state_list; p_node = p_node->next){
|
|
gai_fsm_state_t* p_state = os_list_member_of(p_node, gai_fsm_state_t, node);
|
|
if(transition->from_state_id != p_state->id){
|
|
continue;
|
|
}
|
|
os_list_insert_after(&p_state->transition_list, &transition->node);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
gai_action_status_t gai_fsm_status(gai_fsm_t* self){
|
|
if(self->current_state_p){
|
|
return self->current_state_p->action.status;
|
|
}
|
|
return kGaiActionStatus_UnInitialized;
|
|
}
|
|
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
gai_fsm_transition_t* gai_fsm_find_transition(gai_fsm_t* self, os_int_t from_state_id, os_int_t to_state_id){
|
|
gai_fsm_state_t * p_from_state = 0;
|
|
os_list_node_t* p_node;
|
|
for(p_node = self->state_list.next; p_node!=&self->state_list; p_node = p_node->next){
|
|
gai_fsm_state_t* p_state = os_list_member_of(p_node, gai_fsm_state_t, node);
|
|
if(p_state->id==from_state_id){
|
|
p_from_state = p_state;
|
|
break;
|
|
}
|
|
}
|
|
if(p_from_state==0){
|
|
return 0;
|
|
}
|
|
for(p_node = p_from_state->transition_list.next; p_node!=&p_from_state->transition_list; p_node= p_node->next){
|
|
gai_fsm_transition_t* p_transition = os_list_member_of(p_node, gai_fsm_transition_t, node);
|
|
if(p_transition->to_state_id == to_state_id){
|
|
return p_transition;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
gai_fsm_state_t* gai_fsm_find_state(gai_fsm_t* self, os_int_t state_id){
|
|
os_list_node_t* p_node;
|
|
for(p_node = self->state_list.next; p_node!=&self->state_list; p_node = p_node->next){
|
|
gai_fsm_state_t* p_state = os_list_member_of(p_node, gai_fsm_state_t, node);
|
|
if(p_state->id==state_id){
|
|
return p_state;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
os_bool_t gai_fsm_has_transition(gai_fsm_t* self, os_int_t from_state_id, os_int_t to_state_id){
|
|
return (gai_fsm_find_transition(self, from_state_id, to_state_id)!=0)?OS_TRUE:OS_FALSE;
|
|
}
|
|
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
os_bool_t gai_fsm_has_state(gai_fsm_t* self, os_int_t state_id){
|
|
return (gai_fsm_find_state(self, state_id)!=0)?OS_TRUE:OS_FALSE;
|
|
}
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
void gai_fsm_set_state(gai_fsm_t* self, os_int_t state_id){
|
|
gai_fsm_state_t* p_state = gai_fsm_find_state(self, state_id);
|
|
if(p_state==0){
|
|
return;
|
|
}
|
|
gai_action_Cleanup(&p_state->action);
|
|
self->current_state_p = p_state;
|
|
gai_action_Initialize(&p_state->action);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
|
/* */
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
void gai_fsm_state_init(gai_fsm_state_t* self, os_int_t id,
|
|
gai_action_function_t onInitialize,
|
|
gai_action_update_function_t onUpdate,
|
|
gai_action_function_t onCleanup, void* userdata){
|
|
os_list_init(&self->node);
|
|
self->id = id;
|
|
os_list_init(&self->transition_list);
|
|
gai_action_init(&self->action, onInitialize, onUpdate, onCleanup, userdata);
|
|
}
|
|
|
|
OS_STATIC_FORCE_INLINE
|
|
void gai_fsm_transition_init(gai_fsm_transition_t* self,
|
|
os_int_t from_state_id,
|
|
os_int_t to_state_id,
|
|
gai_fsm_evaluator_t evaluator,
|
|
void* userdata){
|
|
self->evaluator = evaluator;
|
|
self->from_state_id = from_state_id;
|
|
self->to_state_id = to_state_id;
|
|
os_list_init(&self->node);
|
|
self->userdata = userdata;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
|
/* */
|
|
|
|
|
|
void gai_fsm_update(gai_fsm_t* self, void* userdata);
|
|
|
|
#endif /*INCLUDED_GAI_FSM_H*/
|