0%

串口通信时自定义协议的数据包设计与解析方法-2

前言:

前面写了篇串口通信时自定义协议的数据包设计与解析方法的笔记,那篇笔记介绍两种方式,觉得还能改进,于是有了这篇文章。主要介绍一下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

总结:代码算是一个程序框架或结构,未根据具体业务在对应的处理函数里作数据的处理。一旦你掌握了宏的主体思想, 理解这些模板和啥时用啥时进行展开的特点, 就可以用宏来创造出许多精妙的事情来…