自定义通信协议#
1.自定义协议简介#
一般自定义通信协议格式如下:
- 格式一:用帧头和帧长度来确定一个完整的帧
帧头 | 帧长度 | 数据 | 校验 |
---|---|---|---|
0xFF | len | data | crc |
- 格式二:用帧头和帧尾来确定一个完整的帧
帧头 | 数据 | 校验 | 帧尾 |
---|---|---|---|
0xFF | data | crc | 0xFE |
在协议中 <帧头与帧尾属于特殊字节>,如果在 “数据区域” 出现了帧头和帧尾,就可能造成数据解析错误。
格式二出现错误的概率要远高于格式一,因为对于格式二只要数据区域出现0xFE就被接收方认为已经接收到一帧数据;对于格式一来说,除非数据传输错误,就算是数据区域出现0xFF依然会被正确解读。
最安全的做法是将通信协议中的特殊字节进行转义处理。步骤如下:
- 选择一个字节作为转义字节,转义字节也属于特殊字节
- 设计转义规则
2. 转义实现#
eg1:#
- 选择0xFD(除了特殊字节其他应该都可以)作为转义字节
- 制定转义规则:将特殊字节减去0x20
数据发送方遇到特殊字节0xFF,就将0xFF-0x20=0xDF,并在其前面添加转义字节0xFD;数据接收方遇到0xFD就丢弃,并将下一个字节加上0x20作为接收数据。
特殊字节 | 转义后 |
---|---|
0xFF | 0xFD 0xDF |
0xFD | 0xFD 0xDD |
eg2:#
- 选择0xFD(除了特殊字节其他应该都可以)作为转义字节
- 制定转义规则:将特殊字节异或0x20
数据发送方遇到特殊字节0xFF,就将0xFF^0x20=0xDF,并在其前面添加转义字节0xFD;数据接收方遇到0xFD就丢弃,并将下一个字节^0x20作为接收数据。
特殊字节 | 转义后 |
---|---|
0xFF | 0xFD 0xDF |
0xFD | 0xFD 0xDD |
3.收发代码#
- 发送
if((data==0xFF)||(data==0xFD)){
buf[index++]=0xFD;
buf[index++]=data^0x20;
}
- 接收
uint8_t esc_flag=0;
while(!queue_is_empty(&queue)){
protocal_handle.ch = queue_out(&queue);
/* get data */
if(protocal_handle.ch==0xFD){
esc_flag=1;
return;
}
if(esc_flag==1){
esc_flag=0;
protocal_handle.ch ^=0x20;
}
}