330_C语言实现一个简单的状态机

    最近打算认证学习一下CAN通信以及相关的协议栈,尤其是协议栈。我觉得协议栈的定制代表了一种设计的思想。值得一说的是,我在公司从事过相关的工作,但是这次学习我的方式是不借用公司的任何一点信息,更不借助于公司的任何一行代码或者是一点设备。学习的过程,也会是我在网络上遨游探索获取新知识的一个过程。

    为了能够实现一个复杂一点的协议栈,我自己的想法是借助于状态机。或许,这时候诸如MATLAB的stateflow等能够给我帮上忙。但是,我也打算放弃,毕竟试用的版本功能有限,而正式的版本价格昂贵。何况,这是一个大家伙。关于状态机的使用,我打算自己做一个简单的C语言手写版本。做成一个尽量简单的小单元,然后,类似的结构重复应用。或许,这会是我的最终选择。

    关于协议栈,我的想法是做到能用而不追求好用。毕竟,我这次的旅程算是一个自我学习而不是做产品的开发。何况,我现在感觉到自己并没有足够的时间来把这些做到完美。我的工具都简单,这也决定了我自己的软件开发功能或许做的不会特别好。

    回到主题,如何设计我的状态机?其实,状态机的实现思路有很多种,我自己考虑设计的这种状态机单一状态会包含如下的信息。

    事件、当前状态、下一个状态、触发动作。

    其中,一个状态信息的识别标识符为当前状态。类似于一个哈希表、或者数据库的key。而事件,是我临时添加的一个辅助信息,或许后面也会有不同的作用,临时尽量不去实质使用。触发动作,或者切换回调函数,用于辅助实现不同状态切换时候需要完成的功能。这样,我需要的数据结构定义如下:

    其实,完成这部分之后,剩下的就简单了,只剩下了一个查表。定义本次的状态机流转图:

    这会实现一个abc三种状态不断轮流切换的效果。编译测试效果如下:

    结果符合我的预期。最后附件我全部的代码:

#include "stdio.h"
#include "stdint.h"

typedef enum x_event_tag
{
    event_a,
    event_b,
    event_c
} x_event_t;

typedef enum x_state_tag
{
    state_a,
    state_b,
    state_c
} x_state_t, *p_x_state_t;

typedef void (*p_event_action_callback)(void);

typedef struct state_tcb_tag
{
    /* event is just a defination for the process. May be just a process name */
    x_event_t current_event;
    /* current state should be the key for event. */
    x_state_t current_state;
    x_state_t next_state;
    p_event_action_callback p_call_back_func;
}state_tcb_t, *p_state_tcb_t;

void test_act_func_a(void)
{
    printf("action a.\n");
}

void test_act_func_b(void)
{
    printf("action b.\n");
}

void test_act_func_c(void)
{
    printf("action c.\n");
}
const state_tcb_t state_tcb_table[] = {{event_a, state_a, state_b, &test_act_func_a},
                                       {event_b, state_b, state_c, &test_act_func_b},
                                       {event_c, state_c, state_a, &test_act_func_c},};
state_tcb_t state_tcb_demo;

void x_fsm_state_update(state_tcb_t *p_tcb, const state_tcb_t *p_tcb_table, uint32_t table_size)
{
    uint32_t i = 0U;

    for(i = 0U; i < table_size; i++)
    {
        if(p_tcb->current_state == p_tcb_table[i].current_state)
        {
            *p_tcb = p_tcb_table[i];
            p_tcb->p_call_back_func();
            p_tcb->current_state = p_tcb->next_state;
            break;
        }
    }
}

int main(void)
{
    uint32_t i = 0U;
    uint32_t test_idx = 0U;

    printf("start test.\n");

    printf("loop : %d\n", sizeof(state_tcb_table) / sizeof(state_tcb_t));
    printf("%d %d %d\n", state_a, state_b, state_c);
    state_tcb_demo.current_state = state_a;

    for(test_idx = 0; test_idx < 10U; test_idx++)
    {
        printf("--------------------------------------\n");
        printf("test times: %d\n", test_idx);
        x_fsm_state_update(&state_tcb_demo, state_tcb_table, sizeof(state_tcb_table) / sizeof(state_tcb_t));
    }

    return 0;
}

    由于压力大,昨天放纵大吃大喝了一通。今天感觉身体有一点点不适应,好在身体没有报警。以后,还是对我自己的身体好一些吧!类似烧烤之类,或许会满足我们一时间的愉悦,但是总归不算是明智的选择。在此,我决心戒掉了。我希望我的肝脏不再被我自己虐待,因此,我也会尽量早睡早起。祝福看到我学习笔记的人,也能够意识到自己生活中的一点点不合理的因素,不断改进获取新的生活状态。

    有什么技术交流,可以跟我联系。

    邮箱:greyzhang@126.com

    微信:grey0612

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值