嵌入式开发中组包的过程和解析的过程一样吗

在嵌入式产品开发中,我们经常会遇到两个设备之间的通信、设备与服务器的通信、设备和上位机的通信等,很多时候通信协议都是自定义的,所以这就涉及到自定义协议的解析和组包问题。
比如针对下面的这样一个协议:
帧头1 帧头2 字段1 字段2 校验
固定值:0x55 固定值:0xaa 设备id 电压值 前面所有数据异或值
char char short float char
1字节 1字节 2字节 4字节 1字节
数据在发送时涉及到一个大小端的概念,大小端是针对多字节数据的传输,比如上述协议中字段1,假设两字节内容为0x0001,先发送0x01后发送0x00,称为小端模式;先发送0x00后发送0x01,称为大端模式。
假设字段1内容为0x001,字段2内容为0x40533333 (对应为3.3)
假设按照小端方式发送,下面是帧数据:
55 aa 01 00 33 33 53 40 ed
下面来看看如何解析:
若干年前,在第一次面对这种问题时,用的如下傻瓜式的代码方式实现:
#include int main(){    unsigned char rxbuf[9] = {0x55,0xaa,0x01,0x00,0x33,0x33,0x53,0x40,0xed};    short deviceid;    float voltage;    unsigned char check = 0;    int i;    for(i=0;i<8;i++)    {        check ^= rxbuf[i];    }    if(rxbuf[0]==0x55 && rxbuf[1]==0xaa && rxbuf[8]==check )    {        deviceid=(rxbuf[3]<<8)|rxbuf[2];        voltage= *((float *)&rxbuf[4]);        printf(deviceid:%d,deviceid);        printf(voltage:%f,voltage);    }    return 0;}  
简单来说就是硬来,按照数组的先后顺序逐个重组解析,如果协议比较长,代码里会充斥着很多的数组下标,一不小心就数错了。而且如果更改协议的话,代码要改动很多地方。
后来有人告诉我可以定义个结构体,然后使用memcpy函数直接复制过去就完事了。
#include #include #pragma pack(1)struct rxframe{    unsigned char header1;       unsigned char header2;       short deviceid;      float voltage;        unsigned char check;};int main(){    unsigned char rxbuf[9] = {0x55,0xaa,0x01,0x00,0x33,0x33,0x53,0x40,0xed};    struct rxframe rxdata;    unsigned char check = 0;    int i;    for(i=0;i<8;i++)    {        check ^= rxbuf[i];    }    memcpy(&rxdata,rxbuf,sizeof(rxbuf));    if(rxbuf[0]==0x55 && rxbuf[1]==0xaa && rxdata.check==check )    {        printf(deviceid:%d,rxdata.deviceid);        printf(voltage:%f,rxdata.voltage);    }    return 0;}嗯,的确是方便了很多。不过,该方式仅适合小端传输方式。  
再后来,又见到有人用如下代码实现:
#include #include convert.hint main(){    unsigned char rxbuf[9] = {0x55,0xaa,0x01,0x00,0x33,0x33,0x53,0x40,0xed};    short deviceid;    float voltage;    unsigned char check = 0;    int i;    int index = 0;    for(i=0;i<8;i++)    {        check ^= rxbuf[i];    }    if(rxbuf[0]==0x55 && rxbuf[1]==0xaa && rxbuf[8]==check )    {        index += 2;        bytetoshort(rxbuf, &index, &deviceid);        bytetofloat(rxbuf, &index, &voltage);        printf(deviceid:%d,deviceid);        printf(voltage:%f,voltage);    }    return 0;}其中convert.h如下:
#ifndef convert_h#define convert_hvoid  shorttobyte(unsigned char* dest, int* index, short value);void  floattobyte(char* dest, int* index, float value);#endif // convert_hconvert.c如下:#include convert.h#include #include static bool endianflag = 0;void bytetoshort(const unsigned char* source, int* index, short* result){    int i, len = sizeof(short);    char p[len];    memset(p, 0, len);    if(endianflag == 1 )    {        for( i = 0; i < len; i++ )            *(p+i) = *(source + *index + len - i - 1);    }    else    {        for( i = 0; i < len; i++ )            *(p+i) = *(source + *index + i);    }    *result = *((short*)p);    *index += len;}void bytetofloat(unsigned char* source, int* index, float* result){    int i, len = sizeof(float);    char p[len];    memset(p, 0, len);    if(endianflag == 1 )    {        for( i = 0; i < len; i++ )            *(p+i) = *(source + *index + len - i - 1);    }    else    {        for( i = 0; i < len; i++ )            *(p+i) = *(source + *index + i);    }    *result = *((float*)p);    *index += len;}该方法既可以支持小端模式,也可以支持大端模式,使用起来也是比较方便。  
除了上述2个函数,完整的转换包含以下函数,就是将bytes转换为不同的数据类型,以及将不同的数据类型转换为bytes。
#ifndef convert_h#define convert_hvoid  bytetoshort(const unsigned char* source, int* index, short* result);void  bytetoint(unsigned char* source, int* index, int* result);void  bytetolong(char* source, int* index, long long* result);void  bytetofloat(unsigned char* source, int* index, float* result);void  bytetodouble(unsigned char* source, int* index, double* result);void  bytetostring(unsigned char* source, int* index, char* result, int length);void  shorttobyte(unsigned char* dest, int* index, short value);void  inttobyte(char* dest, int* index, int value);void  longtobyte(char* dest, int* index, long long value);void  floattobyte(char* dest, int* index, float value);void  doubletobyte(unsigned char* dest, int* index, double value);void  stringtobyte(char* dest, int* index, int length, char* value);#endif // convert_h  
组包的过程和解析的过程正好相反,这里不再赘述。你在开发中遇到这种问题时,又是如何处理的呢?欢迎留言讨论!


第三代半导体SiC模块厂商中科意创完成数千万元A+轮融资
设备维修的检查方法和操作实践
无人驾驶汽车不再遥远?控制权之争愈发激烈
智融22.5W移动电源双向快充芯片:SW6201
感应电机是什么意思啊_感应电机的工作原理
嵌入式开发中组包的过程和解析的过程一样吗
Moxa推出全新的双RF无线技术,为铁路带来更顺畅的通讯
单片机C51编程规范
我国重复使用火箭研制目标确定
电源的可靠性怎样提高
认识发烧音响器材
SIP网络音频模块SIP2101V/SIP2103V系列说明
俞敏洪:人工智能与教育结结合是未来一大趋势
大众福特联盟谈判终局 共创自动驾驶合资企业
铝合金压铸工艺简介 压铸过程主要工艺参数
智能环境监测系统的结构组成及场景应用案例
关于存储器的工作原理以及市场趋势分析
小米6价格曝光,将再一次带给我们惊喜
智能机器人会改变人类的生产和生活方式吗
2999元!OPPO R11拆解:居然具备生活防水?(组图)