平台 | 内核版本 |
---|---|
RK1108 | Linux3.1 |
结构体相关定义
typedef struct _StMachinePriv {
Queue *queue;
pthread_mutex_t mutex;
StateTable *funcentry;
StateTableDebug *st_debug;
void *arg;
int cur_state;
int status_run;
int table_num;
}StMachinePriv;
重点看下状态标志:
typedef struct _StateTable {
int msg; // 事件消息
int cur_state; // 当前状态
int next_state; // 下一状态
int run; // 执行处理
}StateTable;
状态机类定义
typedef struct _StMachine {
struct _StMachinePriv *priv;
int id;
void *(*initPara)(struct _StMachine *,int size);
int (*getCurrentstate)(struct _StMachine *);
int (*getCurRun)(struct _StMachine *);
/* ---------------------------------------------------------------------------*/
/**
* @brief 发送异步消息
*
* @param
* @param msg 消息值
* @param data 附加数据,需要用initPara初始化
*/
/* ---------------------------------------------------------------------------*/
void (*msgPost)(struct _StMachine *,int msg,void *data);
/* ---------------------------------------------------------------------------*/
/**
* @brief 发送同步消息
*
* @param
* @param msg 消息值
* @param data 附加数据,直接传入参数,无需初始化
*
* @returns -1为未找到当前消息对应执行动作,其他为执行动作返回值
*/
/* ---------------------------------------------------------------------------*/
int (*msgPostSync)(struct _StMachine *,int msg,void *data);
int (*handle)(struct _StMachine *,int result,void *data,void *arg);
void (*destroy)(struct _StMachine **);
}StMachine;
创建状态机
/* ---------------------------------------------------------------------------*/
/**
* @brief stateMachineCreate 创建状态机
*
* @param init_state 初始状态
* @param state_table 状态机表
* @param num 状态机表的数量
* @param id 状态机的ID,区别多个状态机同时运行
* @param handle 状态机处理,
*
* @returns
*/
/* ---------------------------------------------------------------------------*/
StMachine* stateMachineCreate(int init_state,
StateTable *state_table,
int num,
int id,
int (*handle)(StMachine *This,int result,void *data,void *arg),
void *arg,
StateTableDebug *st_debug)
{
StMachine *This = (StMachine *)calloc(1,sizeof(StMachine));
This->priv = (StMachinePriv *)calloc(1,sizeof(StMachinePriv));
This->priv->arg = arg;
This->priv->funcentry = (StateTable *)state_table;
This->priv->table_num = num;
This->priv->cur_state = init_state;
This->priv->queue = queueCreate("stm",QUEUE_BLOCK,sizeof(MsgData));
This->priv->st_debug = st_debug;
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&This->priv->mutex, &mutexattr);
pthread_mutexattr_destroy(&mutexattr);
This->id = id;
This->msgPost = stmMsgPost;
This->msgPostSync = stmMsgPostSync;
This->handle = handle;
This->initPara = stmInitPara;
This->getCurrentstate = stmGetCurrentState;
This->getCurRun = stmGetCurRun;
This->destroy = stmDestroy;
createThread(stmThread,This);
return This;
}
可以看出做了状态机参数的赋值,状态机回调函数的赋值,最后创建状态机处理线程:
static void *stmThread(void *arg)
{
prctl(PR_SET_NAME, __func__, 0, 0, 0);
StMachine *stm= (StMachine *)arg;
MsgData msg_data;
while(1) {
memset(&msg_data,0,sizeof(MsgData));
stm->priv->queue->get(stm->priv->queue,&msg_data);
pthread_mutex_lock(&stm->priv->mutex);
if (stmExecEntry(stm,msg_data.msg))
stm->handle(stm,1,msg_data.data,stm->priv->arg);
else
stm->handle(stm,0,&msg_data.msg,stm->priv->arg);
if (msg_data.data)
free(msg_data.data);
pthread_mutex_unlock(&stm->priv->mutex);
}
pthread_exit(NULL);
return NULL;
}
从上可以看出首先从队列中取出消息,然后状态机执行状态判断和转换:
static int stmExecEntry(StMachine *This,int msg)
{
int num = This->priv->table_num;
StateTable *funcentry = This->priv->funcentry;
for (; num > 0; num--,funcentry++) {
if ( (msg == funcentry->msg)
&& (This->priv->cur_state == funcentry->cur_state)) {
if (This->priv->st_debug) {
DBG_P("[ST->msg:%s,cur:%s,next:%s,do:%s]\n",
This->priv->st_debug->ev[msg],
This->priv->st_debug->st[funcentry->cur_state],
This->priv->st_debug->st[funcentry->next_state],
This->priv->st_debug->todo[funcentry->run]);
}
This->priv->status_run = funcentry->run ;
This->priv->cur_state = funcentry->next_state;
return 1;
}
}
return 0;
}
看下状态机的功能函数
- 发送异步消息
msgPost
- 发送同步消息
msgPostSync
- 处理函数
handle
- 初始化发送状态机消息时带的参数
initPara
- 获取状态机当前状态
getCurrentstate
- 获取状态机运行
getCurRun
- 摧毁状态机
destroy
/**
* @brief stmMsgPost 状态机发送事件消息
*
* @param This
* @param msg 消息
* @param data 附加参数
*/
/* ---------------------------------------------------------------------------*/
static void stmMsgPost(StMachine* This,int msg,void *data)
{
MsgData msg_data;
msg_data.msg = msg;
msg_data.data = data;
This->priv->queue->post(This->priv->queue,&msg_data);
}
static int stmMsgPostSync(StMachine* This,int msg,void *data)
{
int ret = -1;
pthread_mutex_lock(&This->priv->mutex);
if (stmExecEntry(This,msg)) {
printf("%s\n",__func__ );
ret = This->handle(This,1,data,This->priv->arg);
}
pthread_mutex_unlock(&This->priv->mutex);
return ret;
}
/* ---------------------------------------------------------------------------*/
/**
* @brief stmInitPara 初始化发送状态机消息时带的参数
*
* @param This
* @param size 参数大小
*
* @returns
*/
/* ---------------------------------------------------------------------------*/
static void *stmInitPara(StMachine *This,int size)
{
void *para = NULL;
if (size) {
para = (void *) calloc (1,size);
}
return para;
}
/* ---------------------------------------------------------------------------*/
/**
* @brief stmGetCurrentState 获取状态机当前状态
*
* @param This
*
* @returns
*/
/* ---------------------------------------------------------------------------*/
static int stmGetCurrentState(StMachine *This)
{
return This->priv->cur_state;
}
static int stmGetCurRun(StMachine *This)
{
return This->priv->status_run;
}
/* ---------------------------------------------------------------------------*/
/**
* @brief stmDestroy 销毁状态机
*
* @param This
*/
/* ---------------------------------------------------------------------------*/
static void stmDestroy(StMachine **This)
{
if ((*This)->priv)
free((*This)->priv);
if (*This)
free(*This);
*This = NULL;
}
处理函数
我们再看一下我们状态机的处理函数,这里的思想跟中断服务程序有着异曲同工的意义:
static int stmHandle(StMachine *This,int result,void *data,void *arg)
{
if (result) {
return stm_do[This->getCurRun(This)].proc(data,(MyVideo *)arg);
} else {
return stm_do[DO_FAIL].proc(data,(MyVideo *)arg);
}
}
首先看下处理函数对应的结构体
typedef struct _StmDo {
int action;
int (*proc)(void *data,MyVideo *arg);
}StmDo;
static StmDo stm_do[] =
{
{DO_FAIL, stmDoFail},
{DO_NOTHING, stmDoNothing},
{DO_FACE_ON, stmDoFaceOn},
{DO_FACE_OFF, stmDoFaceOff},
{DO_FACE_REGIST, stmDoFaceRegist},
{DO_FACE_RECOGNIZER,stmDoFaceRecognizer},
{DO_TALK_CALLOUT, stmDoTalkCallout},
{DO_TALK_CALLOUTALL,stmDoTalkCalloutAll},
{DO_TALK_CALLIN, stmDoTalkCallin},
{DO_TALK_ANSWER, stmDoTalkAnswer},
{DO_TALK_HANGUP, stmDoTalkHangup},
{DO_TALK_HANGUPALL, stmDoTalkHangupAll},
{DO_CAPTURE, stmDoCapture},
{DO_CAPTURE_NO_UI, stmDoCaptureNoUi},
{DO_RECORD_START, stmDoRecordStart},
{DO_RECORD_STOP, stmDoRecordStop},
{DO_DELAY_SLEEP, stmDoDelaySleepTime},
};
应用
stm = stateMachineCreate(ST_IDLE,
state_table,
sizeof (state_table) / sizeof ((state_table) [0]),
0,
stmHandle,
my_video,
&st_debug);
static StateTable state_table[] =
{
{EV_FACE_ON, ST_IDLE, ST_FACE, DO_FACE_ON},
{EV_FACE_REGIST, ST_FACE, ST_FACE, DO_FACE_REGIST},
{EV_FACE_RECOGNIZER,ST_FACE, ST_FACE, DO_FACE_RECOGNIZER},
}
状态机引擎
static void* threadVideoTimer(void *arg)
{
prctl(PR_SET_NAME, __func__, 0, 0, 0);
while (1) {
if (talk_peer_dev.call_time) {
printf("call time:%d\n", talk_peer_dev.call_time);
if (--talk_peer_dev.call_time == 0) {
stm->msgPost(stm,EV_TALK_HANGUP,NULL);
}
}
sleep(1);
}
return NULL;
}