前言:
前面写了篇串口通信时自定义协议的数据包设计与解析方法的笔记,那篇笔记介绍两种方式,觉得还能改进,于是有了这篇文章。主要介绍一下C语言中宏定义的应用技巧–代码生成器,姑且称作技巧吧!总之,这种方式有优点,也有缺点,各自取舍吧,其可以自动完成许多事情,防止出错概率,带来的缺点–可能可读性差点。
代码如下:
#include <string.h>
#include <stdio.h>
#include<stdint.h>
#define STR(_x) #_x
#define XSTR(_x) STR(_x)
/* 数据包引导码*/
typedef enum {
BOOT_CODE = 0x40,
RETI_CODE = 0xF0,
ERRO_CODE = 0xF4
}packet_boot_code_t;
/* 命令关键字*/
typedef enum {
NONE = 0x00,
version = 0x02,
read = 0x06,
error = 0xf4
}packte_cmd_t;
/* 命令关键字列表*/
#define UART_PARSER_CMDS \
UART_PARSER_CMD( read) \
UART_PARSER_CMD( version) \
UART_PARSER_CMD( error)
/* 数据包*/
typedef struct {
packet_boot_code_t boot_code;
int len;
packte_cmd_t cmd;
int data[64];
int check;
}packet_t;
/***********************************************
* 枚举关键字
***********************************************/
#define SET_CMD_ENUM(x) UART_PARSER_CMD_##x
#define UART_PARSER_CMD( cmd) SET_CMD_ENUM( cmd ),/*注意:逗号哦 */
typedef enum parser_cmds_e
{
UART_PARSER_CMDS
UART_PARSER_CMD_LAST
} parser_cmds_e;
#undef UART_PARSER_CMD
/**************************************************
* 根据关键字定义函数名
**************************************************/
#define SET_HANDLER_FUNC(x) uart_parser_handle_##x
#define UART_PARSER_CMD( cmd)\
static int32_t SET_HANDLER_FUNC(cmd) (int* idata, int ilen, int* odata, int* olen);
UART_PARSER_CMDS
#undef UART_PARSER_CMD
/**************************************************************************
* 构造表结构体定义
**************************************************************************/
typedef struct packet_cmd_table_t
{
packte_cmd_t cmd;
void(*pcallback)(int* idata, int ilen, int* odata, int* olen);
} packet_cmd_table_t;
/**************************************************************************
* 构建结构体表
**************************************************************************/
#define UART_PARSER_CMD( cmd) \
{ cmd , SET_HANDLER_FUNC( cmd )},
packet_cmd_table_t app_cmds_list[] =
{
UART_PARSER_CMDS
{ NONE, NULL,},
};
#undef UART_PARSER_CMD
/**************************************************************************
* 解析数据包函数
**************************************************************************/
void uart_parser_handle(int* idata, int ilen, int* odata, int* olen)
{
packet_cmd_table_t* pcmd_list = app_cmds_list;
packet_t* pcmd = (packet_t*)idata;
while ((pcmd_list->cmd != pcmd->cmd) && (pcmd_list->cmd != 0))
{
pcmd_list++;
}
/* 查表结束,执行表中对应回调函数*/
pcmd_list->pcallback(idata, ilen, odata, olen);
}
/**************************************************************************
* 主函数
**************************************************************************/
void main(void)
{
//测试--待发送的命令包--3组
//int txbuff[5] = { 0x40,0x03,0x02,0xBC,0xbd };
//int txbuff[5] = { 0x40,0x03,0x06,0xBC,0xbd };
int txbuff[5] = { 0x40,0x03,0xf4,0xBC,0xbd };
int rxbuff[64];
int len = 0;
uart_parser_handle(txbuff, 5, rxbuff, &len);
printf("main");
}
/**************************************************************************
* 错误处理函数
**************************************************************************/
int32_t uart_parser_handle_error(int* idata, int ilen, int* odata, int* olen)
{
printf("uart_parser_handle_error\n");
return 1;
}
/**************************************************************************
* 读命令处理函数
**************************************************************************/
int32_t uart_parser_handle_read(int* idata, int ilen, int* data, int* len)
{
printf("uart_parser_handle_error\n");
return 1;
}
/**************************************************************************
* 获取版本处理函数
**************************************************************************/
int32_t uart_parser_handle_version(int* idata, int ilen, int* odata, int* olen)
{
printf("uart_parser_handle_error\n");
return 1;
}
结束:
上面的代码都在vs2019环境测试通过。
执行结果如下:
uart_parser_handle_error
main
总结:代码算是一个程序框架或结构,未根据具体业务在对应的处理函数里作数据的处理。一旦你掌握了宏的主体思想, 理解这些模板和啥时用啥时进行展开的特点, 就可以用宏来创造出许多精妙的事情来…