-
概述
嵌入式设备与外界通信大多是串口,若想通过以太网、WIFI、BLE等通信,则需要外接对应的模块来实现,但每种通信方式对应的网络协议却不相同,
为了实现代码复用及减少模块间的耦合,借用面向对象的方式: 只关注通信的属性:接收,处理,发送; 至于具体的通信行为,则由每个通信协议内部实现。
将上述分为两个模块:通信的属性–> 协议解析器; 具体通信行为–> 命令解析器
-
模块解析
2.1 协议解析器
2.1.1 数据结构
struct ProtocolInterfaceStruct //协议接口
{
void (*Protocol_Init) (Protocol_Init_parameters);
void (*Protocol_process) (Protocol_process_parameters);
void (*Protocol_sender) (Protocol_sender_parameters);
void (*Protocol_error) (Protocol_error_parameters);
}
typedef ProtocolInterfaceStruct *ProtocolInterface;
typedef protocol_struct *Protocol;
struct protocol_struct //协议结构
{
char* protocol_name;
E_PROTOCOL_TYPE protocol_type;
ProtocolInterface protocol_interface;
}
2.1.2 模块伪代码实现
2.1.2.1 协议模块
每个协议创建一个.c文件: uart.c, ble.c, tcp.c ```
在每个.c 文件中创建上述结构体实例。
例如uart.c中:
static struct ProtocolInterface g_uart_protocol_interface =
{
uart_init,
uart_process,
uart_sender,
uart_error
};
static struct protocol_struct g_uart_protocol =
{
"uart_protocol",
P_UART,
&g_uart_protocol_interface;
};
//获取protocol的处理函数
Protocol Uart_Get_Protocol_Handler(void)
{
return &g_uart_protocol;
}
2.1.2.2 通用模块
在外部通用文件里,例如 protocol.c,
Protocol_Init();
Protocol_Process();
Protocol_Sender();
Protocol_error();
通过串口号获取对应protocol 的处理函数:
Protocol Get_Protocol_Handler(Uart_NUM uart_num)
{
Protocol protocol = NULL;
//check uart_num
switch(uart_num)
{
case uart_usart:
protocol = Uart_Get_Protocol_Handler();
case ble_usart:
protocol = Ble_Get_Protocol_Handler();
case tcp_usart:
protocol = Tcp_Get_Protocol_Handler();
default:
break;
}
return protocol;
}
协议接口通用函数,例如 初始化:
void Protocol_Init(Protocol protocol, Protocol_Init_parameters)
{
// 检查protocol
if( protocol == NULL)
{
//debug msg
}
else
{
protocol->protocol_interface->Protocol_Init(Protocol_Init_parameters);
}
}
2.2 命令解析器
命令解析器:设置一个列表数组,数组索引为协议类型,数组元素包括命令,命令对应的处理函数,最大的命令数等, 初始化时先注册对应的cmd 和 handler, 接收到命令
后, 检查命令是否被注册,并调用对应的 cmd_handler ,
2.2.1 数据结构
//命令枚举
typedef enum
{
cmd1,
cmd2,
cmd3,
//```
}Protocol_Cmd;
//命令处理函数指针
typedef Protocol_Return (*Protocol_Handler) (Protocol_Handler_parameters);
命令处理结构体
struct ProtocolCmdHandler
{
Protocol_Cmd cmd; //命令
Protocol_Handler handler; //命令对应的处理函数
}
typedef struct ProtocolCmdHandler* PROTOCOL_CMD_HANDLER;
//命令模块结构体
struct Protocol_CMD_Handler_Struct
{
Uart_NUM uart_num;
PROTOCOL_CMD_HANDLER cmd_handler_list;
uint16_t max_cmd;
bool init_flag;
}
//命令处理列表
static struct Protocol_CMD_Handler_Struct g_protocol_cmd_handler[max_uart_num] = {max_uart_num, NULL, 0, false};
2.2.2 模块伪代码实现
2.2.2.1 通用命令处理函数 protocol_cmd.c
//清空链表
Protocol_Command_Handler_Clear();
//初始化协议对应列表
Protocol_Command_Handler_Init();
//协议处理
Protocol_Command_Handler_Process();
//注册命令处理函数
Protocol_Command_Handler_Register();
//根据协议获取对应命令的处理函数
Protocol_Command_Handler_GetHandle();
//初始化
void Protocol_Command_Handler_Init(Uart_NUM uart_num, uint16_t max_cmd)
{
if((uart_num < max_uart_num) &&
(is_protocol_available(uart_num) == true) &&
g_protocol_cmd_handler[uart_num].init_flag == false)
{
//分配空间
g_protocol_cmd_handler[uart_num].uart_num = uart_num;
g_protocol_cmd_handler[uart_num].max_cmd_handler = max_cmd;
g_protocol_cmd_handler[uart_num].cmd_handler_list = (PROTOCOL_CMD_HANDLER)malloc(max_cmd * sizeof(struct ProtocolCmdHandler));
if(g_protocol_cmd_handler[uart_num].cmd_handler_list != NULL)
{
//初始化有链表非空,清空链表
Protocol_Command_Handler_Clear(uart_num);
}
g_protocol_cmd_handler[uart_num].init_flag = true;
}
}
//获取命令处理函数
PROTOCOL_CMD_HANDLER Protocol_Command_Handler_GetHandle(Uart_NUM uart_num, Protocol_Cmd command)
{
PROTOCOL_CMD_HANDLER handler_p = g_protocol_cmd_handler[uart_num].cmd_handler_list;
PROTOCOL_CMD_HANDLER handler_r = NULL;
if((uart_num < max_uart_num) &&
(g_product_protocol_cmd_handlers[uart_num].cmd_handler_list != NULL) &&
(is_protocol_available(uart_num) == true))
{
while (handler_p->command != max_uart_num)
{
//获取命令对应的处理函数
if (handler_p->command == command)
{
handler_r = handler_p;
break;
}
handler_p++;
}
}
return handler_r;
}
2.2.2.2 协议模块处理
uart_cmd_handle.c
//初始化
uart_cmd_handle_init()
{
//初始化处理列表里usart的结构体
Protocol_Command_Handler_Init(uart_usart, usart_max_cmd);
//usart 命令注册
Protocol_Command_Handler_Register(uart_usart, cmd1, cmd1_handler);
Protocol_Command_Handler_Register(uart_usart, cmd2, cmd2_handler);
}
3. 数据流
串口接收任务uart_task,调用 Protocol_Process 接口处理接收到的数据,Protocol_Process 内调用对应的处理函数,如 uart_process, 处理完成后,
例如需要将 uart 的数据转发到 tcp ,调用 Protocol_Sender, 内部调用 tcp_sender, 将uart 的数据转发到 tcp 上去
版权声明:本文为weixin_45444963原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。