最近打算认证学习一下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;
}
由于压力大,昨天放纵大吃大喝了一通。今天感觉身体有一点点不适应,好在身体没有报警。以后,还是对我自己的身体好一些吧!类似烧烤之类,或许会满足我们一时间的愉悦,但是总归不算是明智的选择。在此,我决心戒掉了。我希望我的肝脏不再被我自己虐待,因此,我也会尽量早睡早起。祝福看到我学习笔记的人,也能够意识到自己生活中的一点点不合理的因素,不断改进获取新的生活状态。
有什么技术交流,可以跟我联系。
微信:grey0612