嵌入式状态机组件

本文最后更新于:17 天前

状态机实现

一、模块简介

状态机组件是模块内部需要进行状态管理时可以使用的一个组件模块,其中业务包含状态机的状态管理,状态机的转换活动、内部活动处理、事件处理等等。
状态机的概念:

( State Machine )状态机是描述事物有限离散状态互相关系的自动化“机器”,是描述事物的抽象数字模型。
什么是状态: 事物任何时刻都有一个状态,同一个状态是指在一段时间内事物具有一定的特征共性。

状态机举例

状态机的四个概念:

  1. 状态:一个状态机至少要包含一个以上的状态,比如上图中一扇门包含打开、关闭两个状态。
  2. 内部活动:在进入状态、退出状态、状态保持时状态机需要执行的动作
  3. 转换活动:状态间的切换动作
  4. 事件:其他模块给状态机发送的消息(事件),状态机根据不同的事件进行处理

其他概念:

  • 伪状态:并非实际的状态节点
  • 历史状态:简单状态的历史状态表示当前状态进入前的上一个状态。复合状态的历史状态表示上从复合状态退出时复合状态的活动状态
    • 浅历史状态:重新进入复合状态时需要进入复合状态的历史状态
    • 深历史状态:进入复合状态的历史状态时历史状态的参数信息需要按照上次退出时更新
  • 活动状态:复合状态的运行态状态

简单状态机举例

简单状态机举例

二、模块设计

2.1需求分析

  • 非功能性需求
    • 正确性
    • 可扩展性
      • 易用性
      • 可读性
      • 可维护性
  • 功能性需求
    • 基本的被大多数场景下应用
    • 包含基本状态机的业务:创建、状态切换、事件处理、活动处理
    • 包含更多复杂状态机需求
      • 复合状态业务
      • 简单状态的历史状态业务
      • 深历史状态、浅历史状态业务

2.2设计原理

  1. 状态节点在状态机上的挂载采用指针数组的方式。因为状态节点在使用的过程中不会被释放所以采用指针数组指向节点地址的方式
  2. 复合状态具有事件处理函数、状态节点指针列表、活动状态。这些在状态机类型上同样存在,同样在简单状态上具有相似的属性特征。所以简单状态、复合状态、状态机类型采用相同的类型。在具体使用的过程中进行区分。
    • “状态机类型也可以看作复合状态类型、复合状态类型也可以看作简单状态类型”
    • “复合状态类型继承简单状态类型,状态机类型继承复合状态类型”
  3. 深历史状态与浅历史状态的区别在于深历史状态在退出时记录了状态的“子状态/参数信息”,所以每个状态在设计的过程中需要考虑状态的特点再决定什么类型。深历史状态和浅历史状态的进入活动需要通过传参进行区分。
  4. 简单状态的历史状态、复合状态的活动状态和历史状态、状态机的活动状态采用同一个成员表示
  5. 状态转换关系需要在软件设计阶段提前设定好,状态机的所有状态转换都应该是可预知的
  6. 状态机的起点是一个顶层状态,顶层状态是一个复合状态
  7. 复合状态属于伪状态,复合状态的内部活动实际是内部活动状态的内部活动
  8. 复合状态具有单独的事件处理方法,这个也是简单状态划分为复合状态的依据:具有相同事件的事件处理方法的一类简单状态可划分为一个复合状态的子状态

三、最佳实践

洗衣机状态转换关系图

洗衣机状态层次关系图

cuteFsm-github

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
typedef struct FsmSimpleNode_t FsmSimpleNode;
typedef struct FsmObj_t FsmObj;
// 转换类型
typedef enum
{
TRANS_RESET,
TRANS_RECORD,
} TRANS_TYPE;

typedef void (*entryHandle)(TRANS_TYPE transType);
typedef void (*exitHandle)(void);
typedef void (*workHandle)(void);
typedef void (*eventHandle)(uint32_t event, uint32_t param);

// 状态机类型
typedef struct FsmObj_t
{
uint8_t active; // 复合状态时为活动状态,简单状态时为历史状态
FsmObj* super; // 所属的父节点
entryHandle entry; // 进入活动
exitHandle exit; // 退出活动
workHandle work; // 轮询活动
eventHandle event; // 事件回调
FsmObj **node; // 子状态列表
} FsmObj;
/**
* @brief 状态机初始化
* @param workObj 最终活动状态
* @param targetObj 初始状态
*/
void FSM_init(FsmObj *workObj,FsmObj *initObj);
/**
* @brief 状态机状态切换 参数重置
* @param workObj 当前状态
* @param workObj 目标状态
*/
void FSM_transState(FsmObj *workObj,FsmObj *targetObj);
/**
* @brief 状态机状态返回 参数不重置
* @param workObj 当前状态
* @param workObj 目标状态
*/
void FSM_backState(FsmObj *workObj,FsmObj *targetObj);
/**
* @brief 状态机事件执行函数
* @param workObj 当前状态
* @param event 事件ID
* @param param 参数ID
*/
void FSM_eventHandle(FsmObj *workObj,uint32_t event,uint32_t param);

/**
* @brief 状态机初始化
* @param workObj 最终活动状态
* @param targetObj 初始状态
**/
void FSM_init(FsmObj *workObj,FsmObj *initObj)
{
ASSERT(NULL != workObj);
ASSERT(NULL != initObj);
workObj = initObj;
if(workObj->entry)
{
workObj->entry(TRANS_RESET);
}
}
static void func_FsmTrans(FsmObj *workObj,FsmObj *targetObj,TRANS_TYPE type)
{
if((NULL != workObj) && (NULL != targetObj))
{
if(workObj->exit)
{
workObj->exit();
}
memcpy(workObj,targetObj,sizeof(targetObj));
if(workObj->entry)
{
workObj->entry(type);
}
}
}
/**
* @brief 状态机状态切换 参数重置
* @param workObj 当前状态
* @param workObj 目标状态
*/
void FSM_transState(FsmObj *workObj,FsmObj *targetObj)
{
func_FsmTrans(workObj,targetObj,TRANS_RESET);
}
/**
* @brief 状态机状态返回 参数不重置
* @param workObj 当前状态
* @param workObj 目标状态
*/
void FSM_backState(FsmObj *workObj,FsmObj *targetObj)
{
ASSERT(NULL != workObj);
ASSERT(NULL != targetObj);
func_FsmTrans(workObj,targetObj,TRANS_RECORD);
}
/**
* @brief 状态机事件执行函数
* @param workObj 当前状态
* @param event 事件ID
* @param param 参数ID
*/
void FSM_eventHandle(FsmObj *workObj,uint32_t event,uint32_t param)
{
ASSERT(NULL != workObj);
if(workObj->event)
{
workObj->event(event,param);
}
FsmObj *workSuper = workObj->super;
while(NULL != workSuper)
{
if(workSuper->event)
{
workSuper->event(event,param);
}
workSuper = workSuper->super;
}
}

嵌入式状态机组件
https://hudaxia.top/2022/01/27/组件-状态机实现/
作者
胡大侠
发布于
2022年1月27日
更新于
2023年3月10日
许可协议