0%

C语言实现一个支持动态扩展的状态机

C语言实现一个支持动态扩展的状态机

Ref: C语言实现有限状态机FSM

状态模式的定义详见:C++设计模式

动态数组实现详见:C语言实现一个支持任意类型的动态数组

本文内容依赖于上文提供的动态数组类型dynamic_arr

基于Ref一文中设计的有限状态机进行了改进,将状态机与其相关的状态、事件以及动作函数通过绑定的形式关联,实现了一定程度上的解耦。支持以字符串的形式动态扩展状态迁移表,从而达到用同样的接口创建多个职责不同的状态机且各自互不干扰的目的。(由于”删除“操作在非服务器程序中可以通过注释”新增“操作实现,因此本文暂未添加删除状态或事件的功能函数)

不足之处:动作函数的形式需统一,待进一步改进。

fsm.h

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
/**
* @copyright (C) Lightshaker
* @date 2023/07/03
*/

#ifndef _FSM_H_
#define _FSM_H_

#include <stdint.h>
#include <stddef.h>
#include "darray.h"

/**
* @brief 状态迁移表单元类型
* @param current_state 当前状态
* @param event 触发事件
* @param action_func 动作函数
* @param next_state 下一个状态
*/
typedef struct
{
const char* current_state;
const char* event;
void (*action_func)(void *);
const char* next_state;
}fsm_table, *fsm_table_ptr;

/**
* @brief 状态机类型
* @param states 动态存储状态
* @param events 动态存储事件
* @param tables 动态存储状态迁移表单元
* @param current_state 当前状态
*/
typedef struct
{
dynamic_arr states;
dynamic_arr events;
dynamic_arr tables;
const char* current_state;
}fsm, *fsm_ptr;

/**
* @brief 初始化状态机
* @param p_fsm 状态机指针
* @param p_table 状态迁移表指针
* @param max_num 状态迁移表最大个数
* @param current_state 当前状态
*/
void fsm_init(fsm_ptr p_fsm);

/**
* @brief 状态迁移与动作执行
* @param p_fsm 状态机指针
* @param event 触发事件索引
* @param param 动作函数参数
*/
void fsm_event_handle(fsm_ptr p_fsm, const char* event, void *param);

/**
* @brief 状态机注册函数
* @fn fsm_state_register 状态注册函数
* @fn fsm_event_register 事件注册函数
* @fn fsm_table_register 迁移表单元注册函数
*/
void fsm_state_register(fsm_ptr p_fsm, const char* state_name);
void fsm_event_register(fsm_ptr p_fsm, const char* event_name);
void fsm_table_register(fsm_ptr p_fsm, fsm_table_ptr p_table);

/**
* @brief 销毁状态机
* @param p_fsm 状态机指针
*/
void fsm_destroy(fsm_ptr p_fsm);

#endif

fsm.c

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
/**
* @copyright (C) Lightshaker
* @date 2023/07/03
*/

#include "fsm.h"

static void fsm_state_transfer(fsm_ptr p_fsm, const char* state)
{
p_fsm->current_state = state;
}

void fsm_event_handle(fsm_ptr p_fsm, const char* event, void *param)
{
fsm_table table;
void (*action_func)(void *) = NULL;
const char* next_state;
const char* current_state = p_fsm->current_state;
uint8_t flag = 0;

for (uint8_t i = 0; i < p_fsm->tables.listsize_; i++)
{
darr_get(&p_fsm->tables, i, &table);
if (event == table.event && current_state == table.current_state)
{
flag = 1;
action_func = table.action_func;
next_state = table.next_state;
break;
}
}
if (flag)
{
if (action_func != NULL)
action_func(param);
fsm_state_transfer(p_fsm, next_state);
}
else
{
// do nothing
}
}

void fsm_init(fsm_ptr p_fsm)
{
p_fsm->states = darr_initiate(sizeof(const char*));
p_fsm->events = darr_initiate(sizeof(const char*));
p_fsm->tables = darr_initiate(sizeof(fsm_table));
}

void fsm_state_register(fsm_ptr p_fsm, const char* state_name)
{
uint8_t flag = 1;
for(int i = 0; i < p_fsm->states.listsize_; i++)
{
char* existed_state = NULL;
darr_get(&p_fsm->states, i, &existed_state);
if (state_name == existed_state)
{
flag = 0;
break;
}
}
if(flag)
{
darr_push(&p_fsm->states, &state_name);
if(p_fsm->states.listsize_ == 1)
p_fsm->current_state = state_name;
}
}

void fsm_event_register(fsm_ptr p_fsm, const char* event_name)
{
uint8_t flag = 1;
for(uint8_t i = 0; i < p_fsm->events.listsize_; i++)
{
char* existed_event = NULL;
darr_get(&p_fsm->events, i, &existed_event);
if (event_name == existed_event)
{
flag = 0;
break;
}
}
if(flag)
darr_push(&p_fsm->events, &event_name);
}

void fsm_table_register(fsm_ptr p_fsm, fsm_table_ptr p_table)
{
uint8_t flag = 1;
for(uint8_t i = 0; i < p_fsm->tables.listsize_; i++)
{
fsm_table table;
darr_get(&p_fsm->tables, i, &table);
if (p_table->current_state == table.current_state && p_table->next_state == table.next_state)
{
flag = 0;
break;
}
}
if(flag)
{
darr_push(&p_fsm->tables, p_table);
fsm_state_register(p_fsm, p_table->current_state);
fsm_state_register(p_fsm, p_table->next_state);
fsm_event_register(p_fsm, p_table->event);
}
}

void fsm_destroy(fsm_ptr p_fsm)
{
darr_clear(&p_fsm->states);
darr_clear(&p_fsm->events);
darr_clear(&p_fsm->tables);
p_fsm = NULL;
}

main.c

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
/**
* @copyright (C) Lightshaker
* @date 2023/07/03
*/

#include <stdio.h>
#include <unistd.h>
#include "fsm.h"

// 状态名称
#define NONE_STATE "none_state"
#define INIT_STATE "init_state"
#define RUNNING_STATE "running_state"
#define STOP_STATE "stop_state"

// 触发事件名称
#define INIT_EVENT "init_event"
#define START_EVENT "start_event"
#define STOP_EVENT "stop_event"

// 动作函数
void init_action(void * param) { printf("init action complete\n"); }
void start_action(void* param) { printf("start action complete.\n"); }
void stop_action(void * param) { printf("stop action complete\n"); }

int main(int argc, char** argv)
{
// 创建状态机
fsm f;

// 初始化状态机
fsm_init(&f);

// 创建状态迁移表
fsm_table table1 = { NONE_STATE, INIT_EVENT, init_action, INIT_STATE };
fsm_table table2 = { INIT_STATE, START_EVENT, start_action, RUNNING_STATE};
fsm_table table3 = { RUNNING_STATE, STOP_EVENT, stop_action, STOP_STATE};

// 注册状态迁移表
fsm_table_register(&f, &table1);
fsm_table_register(&f, &table2);
fsm_table_register(&f, &table3);

// 触发事件
const char* events[3] = { INIT_EVENT, START_EVENT, STOP_EVENT };

// 触发状态迁移
for(int i = 0; i < 3; i++)
{
fsm_event_handle(&f, events[i], NULL);
sleep(1.0);
}

// 销毁状态机
fsm_destroy(&f);
}