下面来介绍一种数据帧和包的封装:
组帧格式:
为了保证数据的可靠性,我们在帧结构中的长度,指令类型,数据,校验和数据包含5A556A69时需要转义,接收时也需要转义,以防止帧解析出现异常。
一帧数据只有一个指令。指令用于控制设备的状态等
组包格式:
这里我们将包头内容包含 版本信息和帧数据的长度信息。
按照该协议,我们可以串口传输,SOCKET TCP传输中来实现数据的发送和接收。
二、 程序实现:
这里我们讨论上位机SOCKET端的组帧和组包,以及解析帧和解包。我们下Qt中编写测试代码。
2.1、frame(帧)类的实现:
1. 新建一个frame类,命名为frame。 在frame.h中我们如下设计
第一步:
设置数据区格式:
#define INT8U unsigned char
#define INT32U unsigned int
#define INT16U unsigned short
# define MAX\_MSG\_LEN 128
typedef struct _Msg_
{
INT8U length;
INT8U crc;
INT8U data[MAX_MSG_LEN];
}Msg,\*pMsg;
第二步:
设计组帧和解析帧
bool PackFrame(Msg src, INT8U \* dst, INT8U \*len); //组包
INT8U UnpackFrame(INT8U ch, Msg \*pmsg); //解包
第三步:
因为我们还要实现对帧中的帧长度,数据区,校验中实现转义,于是我们定义两个函数:
INT8U protocol\_convert(INT8U ch); //转义
INT8U protocol\_deconvert(INT8U ch); //反转义
最后,我们添加校验函数
INT8U CRC8( INT8U\*buffer, INT8U len);
因为在数据转义中,需要对帧的格式进行判断,我们这里设计一个枚举结构
enum FRAME_STATE
{
F_ERROR = -1,
F_HEADER_H,
F_HEADER_L,
F_LENGTH,
F_DATA,
F_CRC,
F_END_H,
F_END_L,
F_OVER,
};
frame.h 预览如下:
#ifndef FRAME\_H
#define FRAME\_H
#include "encrypt/type.h"
#include "encrypt/encrypt.h"
# define MAX\_MSG\_LEN 128
#pragma pack(1)
typedef struct _Msg_
{
INT8U length;
INT8U crc;
INT8U data[MAX_MSG_LEN];
}Msg,\*pMsg;
#pragma pack()
class Frame
{
public:
Frame();
bool PackFrame(Msg src, INT8U \* dst, INT8U \*len); //组包