嵌入式框架Zorb Framework搭建四:状态机的实现

四、最后

  本篇为Zorb
Framework提供了列表功能,而且这个列表可以装载不同类型的数据。可以说是小功能,大作用。

 

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

  版权所有,转载请打赏哟

 

如果你喜欢我的文章,可以通过微信扫一扫给我打赏哟

图片 1

二、状态机设计

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

  初步要提供的功能如下:

  1、可以设置初始状态

  2、可以进行状态转换

  3、可以进行信号调度

  4、最好可以在进入和离开状态的时候可以做一些自定义的事情

  5、最好可以有子状态机

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

 1 /* 状态机结构 */
 2 struct _Fsm
 3 {
 4     uint8_t Level;                  /* 嵌套层数,根状态机层数为1,子状态机层数自增 */
 5                                     /* 注:严禁递归嵌套和环形嵌套 */
 6     List *ChildList;                /* 子状态机列表 */
 7     Fsm *Owner;                     /* 父状态机 */
 8     IFsmState OwnerTriggerState;    /* 当父状态机为设定状态时,才触发当前状态机 */
 9                                     /* 若不设定,则当执行完父状态机,立即运行子状态机 */
10     IFsmState CurrentState;         /* 当前状态 */
11     bool IsRunning;                 /* 是否正在运行(默认关) */
12     
13     /* 设置初始状态 */
14     void (*SetInitialState)(Fsm * const pFsm, IFsmState initialState);
15     
16     /* 运行当前状态机 */
17     bool (*Run)(Fsm * const pFsm);
18     
19     /* 运行当前状态机和子状态机 */
20     bool (*RunAll)(Fsm * const pFsm);
21     
22     /* 停止当前状态机 */
23     bool (*Stop)(Fsm * const pFsm);
24     
25     /* 停止当前状态机和子状态机 */
26     bool (*StopAll)(Fsm * const pFsm);
27     
28     /* 释放当前状态机 */
29     bool (*Dispose)(Fsm * const pFsm);
30     
31     /* 释放当前状态机和子状态机 */
32     bool (*DisposeAll)(Fsm * const pFsm);
33     
34     /* 添加子状态机 */
35     bool (*AddChild)(Fsm * const pFsm, Fsm * const pChildFsm);
36     
37     /* 移除子状态机(不释放空间) */
38     bool (*RemoveChild)(Fsm * const pFsm, Fsm * const pChildFsm);
39     
40     /* 调度状态机 */
41     bool (*Dispatch)(Fsm * const pFsm, FsmSignal const signal);
42     
43     /* 状态转移 */
44     void (*Transfer)(Fsm * const pFsm, IFsmState nextState);
45     
46     /* 状态转移(触发转出和转入事件) */
47     void (*TransferWithEvent)(Fsm * const pFsm, IFsmState nextState);
48 };

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

1 /* 状态机信号0-31保留,用户信号在32以后定义 */
2 enum {
3     FSM_NULL_SIG = 0,
4     FSM_ENTER_SIG,
5     FSM_EXIT_SIG,
6     FSM_USER_SIG_START = 32
7     /* 用户信号请在用户文件定义,不允许在此定义 */
8 };

  其中,0-31为框架信号,用户信号在32之后定义。

  状态机已经设计好了,具体实现请看附件代码或在文末的github地址拉框架源码。

 

嵌入式框架Zorb Framework搭建过程

嵌入式框架Zorb
Framework搭建一:嵌入式环境搭建、调试输出和建立时间系统

嵌入式框架Zorb
Framework搭建二:环形缓冲区的实现

嵌入式框架Zorb
Framework搭建三:列表的实现

嵌入式框架Zorb
Framework搭建四:状态机的实现

嵌入式框架Zorb
Framework搭建五:事件的实现

嵌入式框架Zorb
Framework搭建六:定时器的实现

嵌入式框架Zorb
Framework搭建七:任务的实现

 

三、状态机结果测试

  简单的测试代码如下:

  1 /**
  2   *****************************************************************************
  3   * @file    app_fsm.c
  4   * @author  Zorb
  5   * @version V1.0.0
  6   * @date    2018-06-28
  7   * @brief   状态机测试的实现
  8   *****************************************************************************
  9   * @history
 10   *
 11   * 1. Date:2018-06-28
 12   *    Author:Zorb
 13   *    Modification:建立文件
 14   *
 15   *****************************************************************************
 16   */
 17 
 18 #include "app_fsm.h"
 19 #include "zf_includes.h"
 20 
 21 /* 定义用户信号 */
 22 enum Signal
 23 {
 24     SAY_HELLO = FSM_USER_SIG_START
 25 };
 26 
 27 Fsm *pFsm;        /* 父状态机 */
 28 Fsm *pFsmSon;     /* 子状态机 */
 29 
 30 /* 父状态机状态1 */
 31 static void State1(Fsm * const pFsm, FsmSignal const fsmSignal);
 32 /* 父状态机状态2 */
 33 static void State2(Fsm * const pFsm, FsmSignal const fsmSignal);
 34 
 35 /******************************************************************************
 36  * 描述  :父状态机状态1
 37  * 参数  :-pFsm       当前状态机
 38  *         -fsmSignal  当前调度信号
 39  * 返回  :无
 40 ******************************************************************************/
 41 static void State1(Fsm * const pFsm, FsmSignal const fsmSignal)
 42 {
 43     switch(fsmSignal)
 44     {
 45         case FSM_ENTER_SIG:
 46             ZF_DEBUG(LOG_D, "enter state1\r\n");
 47             break;
 48         
 49         case FSM_EXIT_SIG:
 50             ZF_DEBUG(LOG_D, "exit state1\r\n\r\n");
 51             break;
 52         
 53         case SAY_HELLO:
 54             ZF_DEBUG(LOG_D, "state1 say hello, and want to be state2\r\n");
 55             /* 切换到状态2 */
 56             pFsm->TransferWithEvent(pFsm, State2);
 57             break;
 58     }
 59 }
 60 
 61 /******************************************************************************
 62  * 描述  :父状态机状态2
 63  * 参数  :-pFsm       当前状态机
 64  *         -fsmSignal  当前调度信号
 65  * 返回  :无
 66 ******************************************************************************/
 67 static void State2(Fsm * const pFsm, FsmSignal const fsmSignal)
 68 {
 69     switch(fsmSignal)
 70     {
 71         case FSM_ENTER_SIG:
 72             ZF_DEBUG(LOG_D, "enter state2\r\n");
 73             break;
 74         
 75         case FSM_EXIT_SIG:
 76             ZF_DEBUG(LOG_D, "exit state2\r\n\r\n");
 77             break;
 78         
 79         case SAY_HELLO:
 80             ZF_DEBUG(LOG_D, "state2 say hello, and want to be state1\r\n");
 81             /* 切换到状态1 */
 82             pFsm->TransferWithEvent(pFsm, State1);
 83             break;
 84     }
 85 }
 86 
 87 /******************************************************************************
 88  * 描述  :子状态机状态
 89  * 参数  :-pFsm       当前状态机
 90  *         -fsmSignal  当前调度信号
 91  * 返回  :无
 92 ******************************************************************************/
 93 static void SonState(Fsm * const pFsm, FsmSignal const fsmSignal)
 94 {
 95     switch(fsmSignal)
 96     {
 97         case SAY_HELLO:
 98             ZF_DEBUG(LOG_D, "son say hello only in state2\r\n");
 99             break;
100     }
101 }
102 
103 /******************************************************************************
104  * 描述  :任务初始化
105  * 参数  :无
106  * 返回  :无
107 ******************************************************************************/
108 void App_Fsm_init(void)
109 {
110     /* 创建父状态机,并设初始状态 */
111     Fsm_create(&pFsm);
112     pFsm->SetInitialState(pFsm, State1);
113     
114     /* 创建子状态机,并设初始状态 */
115     Fsm_create(&pFsmSon);
116     pFsmSon->SetInitialState(pFsmSon, SonState);
117     
118     /* 设置子状态机仅在父状态State2触发 */
119     pFsmSon->OwnerTriggerState = State2;
120     
121     /* 把子状态机添加到父状态机 */
122     pFsm->AddChild(pFsm, pFsmSon);
123     
124     /* 运行状态机 */
125     pFsm->RunAll(pFsm);
126 }
127 
128 /******************************************************************************
129  * 描述  :任务程序
130  * 参数  :无
131  * 返回  :无
132 ******************************************************************************/
133 void App_Fsm_process(void)
134 {
135     ZF_DELAY_MS(1000);
136     /* 每1000ms调度状态机,发送SAY_HELLO信号 */
137     pFsm->Dispatch(pFsm, SAY_HELLO);
138 }
139 
140 /******************************** END OF FILE ********************************/

  结果:

state1 say hello, and want to be state2
exit state1

enter state2
son say hello only in state2
state2 say hello, and want to be state1
exit state2

enter state1
state1 say hello, and want to be state2
exit state1

enter state2
son say hello only in state2
state2 say hello, and want to be state1
exit state2

enter state1
state1 say hello, and want to be state2
exit state1

省略...

 

一、前言

  在这一篇中,我们将为Zorb
Framework提供列表功能。列表是我最喜欢用的数据结构,没有之一。在只要涉及到管理对象不止一个的时候,我就会想到列表。后面将要设计的状态机、事件、定时器和任务等等都需要列表的支持,可以说列表在整个框架里边是必不可少的一个功能。

 

我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮。

我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮。

四、最后

  本篇为Zorb
Framework提供了状态机功能,复杂的状态转换关系被分解成了一个个状态函数,然后在状态函数中仅仅需要处理本状态出现的情况,忽然感觉世界变得简单很多。后面再配上即将为框架添加的事件功能,会让状态机的功能发挥到极致。

 

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

  版权所有,转载请打赏哟

 

如果你喜欢我的文章,可以通过微信扫一扫给我打赏哟

图片 1

三、列表结果测试

  简单的测试代码如下:

  1 /**
  2   *****************************************************************************
  3   * @file    app_list.c
  4   * @author  Zorb
  5   * @version V1.0.0
  6   * @date    2018-06-28
  7   * @brief   列表测试的实现
  8   *****************************************************************************
  9   * @history
 10   *
 11   * 1. Date:2018-06-28
 12   *    Author:Zorb
 13   *    Modification:建立文件
 14   *
 15   *****************************************************************************
 16   */
 17 
 18 #include "app_list.h"
 19 #include "zf_includes.h"
 20 #include "string.h"
 21 
 22 /* 列表指针 */
 23 List *pBookList;
 24 
 25 /* 书本数据结构 */
 26 typedef struct _Book
 27 {
 28     uint32_t Index; /* 索引 */
 29     char Name[10];  /* 书名 */
 30 } Book;
 31 
 32 /******************************************************************************
 33  * 描述  :任务初始化
 34  * 参数  :无
 35  * 返回  :无
 36 ******************************************************************************/
 37 void App_List_init(void)
 38 {
 39     /* 创建列表 */
 40     List_create(&pBookList);
 41 }
 42 
 43 /******************************************************************************
 44  * 描述  :任务程序
 45  * 参数  :无
 46  * 返回  :无
 47 ******************************************************************************/
 48 void App_List_process(void)
 49 {
 50     uint32_t i;
 51     ListNode *pNode;
 52     Book *pBook;
 53     
 54     ZF_DEBUG(LOG_D, "book list count before adding data is %d\r\n",
 55         pBookList->Count);
 56     
 57     /* 填充10个数据 */
 58     for (i = 0; i < 10; i++)
 59     {
 60         /* 创建节点 */
 61         List_mallocNode(&pNode, (void **)&pBook, sizeof(Book));
 62         
 63         /* 填充节点内容 */
 64         pBook->Index = i;
 65         strcpy(pBook->Name, "book x");
 66         pBook->Name[5] = '0' + i;
 67         
 68         /* 添加到列表 */
 69         pBookList->Add(pBookList, pNode);
 70     }
 71     
 72     ZF_DEBUG(LOG_D, "book list count after adding data is %d\r\n",
 73         pBookList->Count);
 74     
 75     /* 读出第3个数据看是否正确 */
 76     pBook = (Book *)pBookList->GetElementDataAt(pBookList, 2);
 77     
 78     ZF_DEBUG(LOG_D, "book index is %d\r\n", pBook->Index);
 79     ZF_DEBUG(LOG_D, "book name is %s\r\n", pBook->Name);
 80     
 81     ZF_DEBUG(LOG_D, "\r\n");
 82     
 83     /* 删除第5个数据 */
 84     pBookList->DeleteElementAt(pBookList, 4);
 85     
 86     ZF_DEBUG(LOG_D, "book list count after deleteing data is %d\r\n",
 87         pBookList->Count);
 88     
 89     /* 显示现有数据 */
 90     for (i = 0; i < pBookList->Count; i++)
 91     {
 92         pBook = (Book *)pBookList->GetElementDataAt(pBookList, i);
 93         
 94         ZF_DEBUG(LOG_D, "\r\n");
 95         ZF_DEBUG(LOG_D, "book index is %d\r\n", pBook->Index);
 96         ZF_DEBUG(LOG_D, "book name is %s\r\n", pBook->Name);
 97     }
 98     
 99     while(1);
100 }
101 
102 /******************************** END OF FILE ********************************/

  结果:

book list count before adding data is 0
book list count after adding data is 10
book index is 2
book name is book 2

book list count after deleteing data is 9

book index is 0
book name is book 0

book index is 1
book name is book 1

book index is 2
book name is book 2

book index is 3
book name is book 3

book index is 5
book name is book 5

book index is 6
book name is book 6

book index is 7
book name is book 7

book index is 8
book name is book 8

book index is 9
book name is book 9

 

嵌入式框架Zorb Framework搭建过程

嵌入式框架Zorb
Framework搭建一:嵌入式环境搭建、调试输出和建立时间系统

嵌入式框架Zorb
Framework搭建二:环形缓冲区的实现

嵌入式框架Zorb
Framework搭建三:列表的实现

嵌入式框架Zorb
Framework搭建四:状态机的实现

嵌入式框架Zorb
Framework搭建五:事件的实现

嵌入式框架Zorb
Framework搭建六:定时器的实现

嵌入式框架Zorb
Framework搭建七:任务的实现

 

二、列表设计

  我们先来看看要实现的列表提供什么功能:

  初步要提供的功能如下:

  1、可以在指定位置增加数据

  2、可以在指定位置删除数据

  3、可以知道列表数据的个数

  4、可以清空列表

  5、可以不释放数据,仅仅把数据移出列表

  6、可以根据数据获取它所在的索引

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

 1 /* 列表节点结构 */
 2 typedef struct _ListNode
 3 {
 4     bool IsExternData;          /* 是否外部数据,是则销毁时不释放 */
 5     uint8_t *pData;             /* 指向数据的指针 */
 6     uint32_t Size;              /* 数据的大小 */
 7     struct _ListNode *Next;     /* 指向下一个节点 */
 8 } ListNode;
 9 
10 /* 列表结构 */
11 typedef struct _List
12 {
13     ListNode *pRootNode;        /* 指向根节点数据 */
14     uint32_t Count;             /* 节点个数 */
15     
16     /* 在尾端增加节点 */
17     bool (*Add)(struct _List * const pList, ListNode *pNode);
18     
19     /* 删除节点(释放空间) */
20     bool (*Delete)(struct _List * const pList, ListNode *pNode);
21     
22     /* 移除节点(不释放空间) */
23     bool (*Remove)(struct _List * const pList, ListNode *pNode);
24     
25     /* 返回指定索引处的节点的指针 */
26     bool (*GetElementAt)(struct _List * const pList, uint32_t index,
27         ListNode **ppNode);
28     
29     /* 返回数据区指向data的节点的指针 */
30     bool (*GetElementByData)(struct _List * const pList, void *pdata,
31         ListNode **ppNode);
32     
33     /* 返回指定索引处的节点的数据缓冲区的指针 */
34     void *(*GetElementDataAt)(struct _List * const pList, uint32_t index);
35     
36     /* 返回节点的索引 */
37     bool (*GetElementIndex)(struct _List * const pList, ListNode *pNode,
38         uint32_t *pIndex);
39     
40     /* 在指定索引处增加节点 */
41     bool (*AddElementAt)(struct _List * const pList, uint32_t index,
42         ListNode *pNode);
43     
44     /* 在指定索引处删除节点(释放空间) */
45     bool (*DeleteElementAt)(struct _List * const pList, uint32_t index);
46     
47     /* 在指定索引处移除节点(不释放空间) */
48     bool (*RemoveElementAt)(struct _List * const pList, uint32_t index);
49     
50     /* 清空列表(释放空间) */
51     bool (*Clear)(struct _List * const pList);
52     
53     /* 释放列表(释放空间) */
54     bool (*Dispose)(struct _List * const pList);
55 } List;

  为了实现动态列表,在列表中提供了一个Dispose的功能。

  列表已经设计好了,具体实现请看附件代码或在文末的github地址拉框架源码。

 

一、前言

  在这一篇中,我们将为Zorb
Framework提供状态机功能。中小型嵌入式程序说白了就是由各种状态机组成,因此掌握了如何构建状态机,开发嵌入式应用程序可以说是手到拈来。简单的状态机可以用Switch-Case实现,但复杂一点的状态机再继续使用Switch-Case的话,层次会变得比较乱,不方便维护。因此我们为Zorb
Framework提供了函数式状态机。