新闻| 论坛| 博客| 在线研讨会
一个轻量级的开源嵌入式状态机框架
xiaomaidashu| 2023-12-18 16:48:53 阅读:411 发布文章

前言

Zorb Framework是一个基于面向对象的思想来搭建一个轻量级的嵌入式框架。

本次分享的是Zorb Framework的状态机的实现。中小型嵌入式程序说白了就是由各种状态机组成,因此掌握了如何构建状态机,开发嵌入式应用程序可以说是手到拈来。

简单的状态机可以用Switch-Case实现,但复杂一点的状态机再继续使用Switch-Case的话,层次会变得比较乱,不方便维护。

因此我们为Zorb Framework提供了函数式状态机。

项目地址:https://github.com/54zorb/Zorb-Framework

状态机的功能

我们先来看看要实现的状态机提供什么功能:初步要提供的功能如下:

  1. 可以设置初始状态;
  2. 可以进行状态转换;
  3. 可以进行信号调度;
  4. 最好可以在进入和离开状态的时候可以做一些自定义的事情;
  5. 最好可以有子状态机;
数据结构

因此,初步设计的数据结构如下:

`/* 状态机结构 */ struct _Fsm { uint8_t Level; /* 嵌套层数,根状态机层数为1,子状态机层数自增 */ /* 注:严禁递归嵌套和环形嵌套 */ List *ChildList; /* 子状态机列表 */ Fsm *Owner; /* 父状态机 */ IFsmState OwnerTriggerState; /* 当父状态机为设定状态时,才触发当前状态机 */ /* 若不设定,则当执行完父状态机,立即运行子状态机 */ IFsmState CurrentState; /* 当前状态 */ bool IsRunning; /* 是否正在运行(默认关) */ /* 设置初始状态 */ void (*SetInitialState)(Fsm * const pFsm, IFsmState initialState); /* 运行当前状态机 */ bool (*Run)(Fsm * const pFsm); /* 运行当前状态机和子状态机 */ bool (*RunAll)(Fsm * const pFsm); /* 停止当前状态机 */ bool (*Stop)(Fsm * const pFsm); /* 停止当前状态机和子状态机 */ bool (*StopAll)(Fsm * const pFsm); /* 释放当前状态机 */ bool (*Dispose)(Fsm * const pFsm); /* 释放当前状态机和子状态机 */ bool (*DisposeAll)(Fsm * const pFsm); /* 添加子状态机 */ bool (*AddChild)(Fsm * const pFsm, Fsm * const pChildFsm); /* 移除子状态机(不释放空间) */ bool (*RemoveChild)(Fsm * const pFsm, Fsm * const pChildFsm); /* 调度状态机 */ bool (*Dispatch)(Fsm * const pFsm, FsmSignal const signal); /* 状态转移 */ void (*Transfer)(Fsm * const pFsm, IFsmState nextState); /* 状态转移(触发转出和转入事件) */ void (*TransferWithEvent)(Fsm * const pFsm, IFsmState nextState); };

关于信号,Zorb Framework做了以下定义:

/* 状态机信号0-31保留,用户信号在32以后定义 */ enum { FSM_NULL_SIG = 0, FSM_ENTER_SIG, FSM_EXIT_SIG, FSM_USER_SIG_START = 32 /* 用户信号请在用户文件定义,不允许在此定义 */ };
创建状态机

实现代码如下:

bool Fsm_create(Fsm ** ppFsm) { Fsm *pFsm; ZF_ASSERT(ppFsm != (Fsm **)0) /* 分配空间 */ pFsm = ZF_MALLOC(sizeof(Fsm)); if (pFsm == NULL) { ZF_DEBUG(LOG_E, "malloc fsm space errorrn"); return false; } /* 初始化成员 */ pFsm->Level = 1; pFsm->ChildList = NULL; pFsm->Owner = NULL; pFsm->OwnerTriggerState = NULL; pFsm->CurrentState = NULL; pFsm->IsRunning = false; /* 初始化方法 */ pFsm->SetInitialState = Fsm_setInitialState; pFsm->Run = Fsm_run; pFsm->RunAll = Fsm_runAll; pFsm->Stop = Fsm_stop; pFsm->StopAll = Fsm_stopAll; pFsm->Dispose = Fsm_dispose; pFsm->DisposeAll = Fsm_disposeAll; pFsm->AddChild = Fsm_addChild; pFsm->RemoveChild = Fsm_removeChild; pFsm->Dispatch = Fsm_dispatch; pFsm->Transfer = Fsm_transfer; pFsm->TransferWithEvent = Fsm_transferWithEvent; /* 输出 */ *ppFsm = pFsm; return true; }
调度状态机

实现代码如下:

`/****************************************************************************** * 描述 :调度状态机 * 参数 :(in)-pFsm 状态机指针 * (in)-signal 调度信号 * 返回 :-true 成功 * -false 失败 ******************************************************************************/ bool Fsm_dispatch(Fsm * const pFsm, FsmSignal const signal) { /* 返回结果 */ bool res = false; ZF_ASSERT(pFsm != (Fsm *)0) if (pFsm->IsRunning) { if (pFsm->ChildList != NULL && pFsm->ChildList->Count > 0) { uint32_t i; Fsm * pChildFsm; for (i = 0; i < pFsm->ChildList->Count; i++) { pChildFsm = (Fsm *)pFsm->ChildList ->GetElementDataAt(pFsm->ChildList, i); if (pChildFsm != NULL) { Fsm_dispatch(pChildFsm, signal); } } } if (pFsm->CurrentState != NULL) { /* 1:根状态机时调度 2:没设置触发状态时调度 3:正在触发状态时调度 */ if (pFsm->Owner == NULL || pFsm->OwnerTriggerState == NULL || pFsm->OwnerTriggerState == pFsm->Owner->CurrentState) { pFsm->CurrentState(pFsm, signal); res = true; } } } return res; }

篇幅有限,其它接口实现可阅读:

https://github.com/54zorb/Zorb-Framework

状态机测试
/** ***************************************************************************** * @file app_fsm.c * @author Zorb * @version V1.0.0 * @date 2018-06-28 * @brief 状态机测试的实现 ***************************************************************************** * @history * * 1. Date:2018-06-28 * Author:Zorb * Modification:建立文件 * ***************************************************************************** */ #include "app_fsm.h" #include "zf_includes.h" /* 定义用户信号 */ enum Signal { SAY_HELLO = FSM_USER_SIG_START }; Fsm *pFsm; /* 父状态机 */ Fsm *pFsmSon; /* 子状态机 */ /* 父状态机状态1 */ static void State1(Fsm * const pFsm, FsmSignal const fsmSignal); /* 父状态机状态2 */ static void State2(Fsm * const pFsm, FsmSignal const fsmSignal); /****************************************************************************** * 描述 :父状态机状态1 * 参数 :-pFsm 当前状态机 * -fsmSignal 当前调度信号 * 返回 :无 ******************************************************************************/ static void State1(Fsm * const pFsm, FsmSignal const fsmSignal) { switch(fsmSignal) { case FSM_ENTER_SIG: ZF_DEBUG(LOG_D, "enter state1rn"); break; case FSM_EXIT_SIG: ZF_DEBUG(LOG_D, "exit state1rnrn"); break; case SAY_HELLO: ZF_DEBUG(LOG_D, "state1 say hello, and want to be state2rn"); /* 切换到状态2 */ pFsm->TransferWithEvent(pFsm, State2); break; } } /****************************************************************************** * 描述 :父状态机状态2 * 参数 :-pFsm 当前状态机 * -fsmSignal 当前调度信号 * 返回 :无 ******************************************************************************/ static void State2(Fsm * const pFsm, FsmSignal const fsmSignal) { switch(fsmSignal) { case FSM_ENTER_SIG: ZF_DEBUG(LOG_D, "enter state2rn"); break; case FSM_EXIT_SIG: ZF_DEBUG(LOG_D, "exit state2rnrn"); break; case SAY_HELLO: ZF_DEBUG(LOG_D, "state2 say hello, and want to be state1rn"); /* 切换到状态1 */ pFsm->TransferWithEvent(pFsm, State1); break; } } /****************************************************************************** * 描述 :子状态机状态 * 参数 :-pFsm 当前状态机 * -fsmSignal 当前调度信号 * 返回 :无 ******************************************************************************/ static void SonState(Fsm * const pFsm, FsmSignal const fsmSignal) { switch(fsmSignal) { case SAY_HELLO: ZF_DEBUG(LOG_D, "son say hello only in state2rn"); break; } } /****************************************************************************** * 描述 :任务初始化 * 参数 :无 * 返回 :无 ******************************************************************************/ void App_Fsm_init(void) { /* 创建父状态机,并设初始状态 */ Fsm_create(&pFsm); pFsm->SetInitialState(pFsm, State1); /* 创建子状态机,并设初始状态 */ Fsm_create(&pFsmSon); pFsmSon->SetInitialState(pFsmSon, SonState); /* 设置子状态机仅在父状态State2触发 */ pFsmSon->OwnerTriggerState = State2; /* 把子状态机添加到父状态机 */ pFsm->AddChild(pFsm, pFsmSon); /* 运行状态机 */ pFsm->RunAll(pFsm); } /****************************************************************************** * 描述 :任务程序 * 参数 :无 * 返回 :无 ******************************************************************************/ void App_Fsm_process(void) { ZF_DELAY_MS(1000); /* 每1000ms调度状态机,发送SAY_HELLO信号 */ pFsm->Dispatch(pFsm, SAY_HELLO); } /******************************** END OF FILE ********************************/
测试结果

图片

测试结果

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客