当前位置:网站首页>通讯协议设计与实现
通讯协议设计与实现
2022-07-07 10:31:00 【咕咚.萌西】
通讯协议分类
硬件协议
在物理层进行数据传输时,发送端和接收端之间需要遵循相应的硬件协议,例如我们通过IO采集一个电压信号,当输入电压高于2V时候,硬件会认为采集到一个高电平,低于2V则认为是一个低电平。常见的光纤,串口,CAN总线我们将其划分为硬件协议,他们是数据传输的载体。
软件协议
根据总线的物理特性,在此之上可以设计出各种各样的软件协议,此处涉及到的协议讲解部分为软件协议,后面简称协议。例如通过IO可以设计出SPI通讯协议和IIC协议,通过CAN总线可以设计出CANOpen协议,通过串口可以设计出Modbus协议。
帧格式
在硬件基础上进行数据传输时需要设计一个帧格式,例如串口传输的数据通常是以字节为单位,那么协议设计时传输的最小的单位也必须是字节,通讯帧通常分为两类,一类是定长帧,一类是不定长帧。
定长帧
所有帧长度都相同,接收者先接收完指定长度字符,然后根据报文类型做进一步处理,这种协议可拓展性较低,适合简单数据传输。
不定长帧
第一种:通讯双方根据功能划分,划分为不同的报文类型,每种类型的长度不尽相同,但是接收者和发送者对每种类型的数据长度都是提前约定好的,传输数据中不包含长度信息。
第二种:帧长度不固定,每帧可以分为三个部分,帧头,数据,校验,其中帧头和校验的长度是固定的,数据的长度是可变的,帧头中包含长度信息,当接收完一个完整的帧头后进行解析,通过读取其中的长度信息获取到剩余数据的长度,然后继续接收,直到接收到校验,一帧数据接收完成,然后进行数据的校验,校验成功进行下一步处理,这种情况下接收端在发送前并不清楚需要接收的数据长度,相比第一种协议可拓展性更强,可以用于传输文件等超长信息。
通讯帧设计
| 起始标识 | 帧头 | 数据 | 校验 | 结束标识 |
|---|---|---|---|---|
| 1 byte | 16 bytes | n bytes | 1 byte | 1 byte |
通讯报文主要分成两个部分:
- 用户层包含帧头和数据,这部分定义了报文的类型和传输的内容
- 传输层为了保证数据的准确性和完整性,加上了起始标识,校验和结束标识
起始标志和结束标志
为了避免在数据中出现起始标识和结束标识,因此对数据中出现该字符时需要进行转义。
| 起始标识 | 结束标识 | 0xdb |
|---|---|---|
| 0x55 | 0x56 | 0xdb |
| 0xdb 0xdc | 0xdb 0xdd | 0xdb 0xde |
帧头
| 类型 | 指令 | 帧号 | 总长度 | 数据长度 |
|---|---|---|---|---|
| 2 byte | 2 byte | 2 bytes | 4 bytes | 4 bytes |
- 类型和指令用于告知接收者如何处理数据
- 帧号和总长度用于传输大数据,例如文件
- 数据长度则代表数据区的字节数
数据
| Data |
|---|
| n bytes |
数据长度不固定,是可变的,接收端会根据帧头中包含的长度信息接收数据,如果没有数据则直接接收帧尾
校验
| CRC |
|---|
| 1 bytes |
帧尾部分包含1字节CRC,用于对整个数据进行校验,如果采用TCP这种可靠通讯,可以去掉CRC,CRC是为了防止传输过程中出错
帧数据结构
typedef struct
{
uint16_t type;
uint16_t cmd;
uint16_t index;
uint32_t total;
uint32_t len;
} msg_header_t;
typedef struct
{
msg_header_t header;
uint8_t payload[];
} msg_t;
- 按照C语言的默认边界对齐方式,帧头大小为16字节。
- 数据长度不固定此处使用一个指针来表示。
- msg_t大小为20字节。
通讯帧传输
发送报文
uint32_t msg_data_convert(uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len)
{
int i = 0;
int j = 0;
uint8_t *p = in;
for (; (i < in_len) && (j < (out_len - 1)); i++, p++)
{
if (MSG_BEGIN_FLAG == *p)
{
out[j++] = 0xdb;
out[j++] = 0xdc;
}
else if (MSG_END_FLAG == *p)
{
out[j++] = 0xdb;
out[j++] = 0xdd;
}
else
{
out[j++] = *p;
if (0xdb == *p)
{
out[j++] = 0xde;
}
}
}
DEBUG_ASSERT(j < (out_len - 1));
return j;
}
bool msg_create(msg_parser_t *obj, msg_type_def type, msg_cmd_def cmd, uint32_t index, uint32_t total, uint8_t *payload, uint32_t len)
{
uint8_t crc = 0;
bool ret = false;
msg_t msg = {
0};
uint32_t offset = 0;
if ((payload && (len > 0)) || (!payload && (len == 0)))
{
ret = true;
}
msg.header.type = (uint16_t)type;
msg.header.cmd = (uint16_t)cmd;
msg.header.index = index;
msg.header.total = total;
msg.header.len = len;
msg.payload = payload;
crc = msg_parser_calculate_crc(0, (uint8_t *)&msg, sizeof(msg_header_t));
crc = msg_parser_calculate_crc(crc, msg.payload, msg.header.len);
obj->msg_send_buffer[offset++] = MSG_BEGIN_FLAG;
/* 对数据中出现帧头和帧尾的情况进行转义 */
offset += msg_data_convert((uint8_t *)&msg, sizeof(msg_header_t), &obj->msg_send_buffer[offset], sizeof(obj->msg_send_buffer) - offset);
offset += msg_data_convert(msg.payload, msg.header.len, &obj->msg_send_buffer[offset], sizeof(obj->msg_send_buffer) - offset);
offset += msg_data_convert(&crc, sizeof(crc), &obj->msg_send_buffer[offset], sizeof(obj->msg_send_buffer) - offset);
obj->msg_send_buffer[offset++] = MSG_END_FLAG;
/* 通过串口发送报文 */
com_write(obj->com_drv, obj->msg_send_buffer, offset);
return ret;
}
接收报文
msg_t *msg_parser_recv(msg_parser_t *obj)
{
uint8_t temp = 0;
uint32_t crc = 0;
uint8_t recv_crc = 0;
uint32_t recv_cnt = 0;
msg_t *ret = &obj->recv_msg;
/* 接收帧头 */
do
{
com_read_byte(obj->com_drv, &temp, osWaitForever);
} while (MSG_BEGIN_FLAG != temp);
/* 接收剩余数据 */
do
{
com_read_byte(obj->com_drv, &temp, osWaitForever);
if (temp == 0xdb)
{
com_read_byte(obj->com_drv, &temp, osWaitForever);
if (0xdc == temp)
obj->msg_recv_buffer[recv_cnt++] = MSG_BEGIN_FLAG;
else if (0xdd == temp)
obj->msg_recv_buffer[recv_cnt++] = MSG_END_FLAG;
else if (0xde == temp)
obj->msg_recv_buffer[recv_cnt++] = 0xdb;
}
else
{
obj->msg_recv_buffer[recv_cnt++] = temp;
}
} while ((MSG_END_FLAG != temp) && (recv_cnt < sizeof(obj->msg_recv_buffer)));
if (recv_cnt < sizeof(obj->msg_recv_buffer))
{
/* 获取帧头 */
memcpy(&ret->header, obj->msg_recv_buffer, sizeof(msg_header_t));
if (recv_cnt == (sizeof(msg_header_t) + 2 + ret->header.len))
{
/* 获取数据 */
ret->payload = obj->msg_recv_buffer + sizeof(msg_header_t);
/* 获取校验 */
recv_crc = obj->msg_recv_buffer[recv_cnt - 2];
/* 计算校验 */
crc = msg_parser_calculate_crc(0, (uint8_t *)ret, sizeof(msg_header_t));
crc = msg_parser_calculate_crc(crc, ret->payload, ret->header.len);
if (recv_crc != crc)
{
ret = NULL;
}
}
else
{
ret = NULL;
}
}
else
{
ret = NULL;
}
return ret;
}
边栏推荐
- Static routing assignment of network reachable and telent connections
- Static comprehensive experiment
- Solve server returns invalid timezone Go to ‘Advanced’ tab and set ‘serverTimezone’ property manually
- IPv6 experiment
- 关于 Web Content-Security-Policy Directive 通过 meta 元素指定的一些测试用例
- EPP+DIS学习之路(1)——Hello world!
- Is it safe to open an account in Ping An Securities mobile bank?
- Xiaohongshu microservice framework and governance and other cloud native business architecture evolution cases
- How to use PS link layer and shortcut keys, and how to do PS layer link
- 盘点JS判断空对象的几大方法
猜你喜欢
![[statistical learning methods] learning notes - improvement methods](/img/c5/515f171995da8e424de290228b54f8.png)
[statistical learning methods] learning notes - improvement methods

静态Vxlan 配置

Attack and defense world ----- summary of web knowledge points

H3C HCl MPLS layer 2 dedicated line experiment

ps链接图层的使用方法和快捷键,ps图层链接怎么做的

Xiaohongshu microservice framework and governance and other cloud native business architecture evolution cases

Pule frog small 5D movie equipment | 5D movie dynamic movie experience hall | VR scenic area cinema equipment

How to use PS link layer and shortcut keys, and how to do PS layer link

Sonar:cognitive complexity

【玩转 RT-Thread】 RT-Thread Studio —— 按键控制电机正反转、蜂鸣器
随机推荐
【PyTorch实战】用PyTorch实现基于神经网络的图像风格迁移
leetcode刷题:二叉树27(删除二叉搜索树中的节点)
OSPF exercise Report
Is it safe to open an account in Ping An Securities mobile bank?
When OSPF specifies that the connection type is P2P, it enables devices on both ends that are not in the same subnet to Ping each other
SQL lab 26~31 summary (subsequent continuous update) (including parameter pollution explanation)
Sonar:cognitive complexity
爱可可AI前沿推介(7.7)
Error in compiling libssl
Unity 贴图自动匹配材质工具 贴图自动添加到材质球工具 材质球匹配贴图工具 Substance Painter制作的贴图自动匹配材质球工具
Is it safe to open Huatai's account in kainiu in 2022?
数据库系统原理与应用教程(007)—— 数据库相关概念
【PyTorch实战】图像描述——让神经网络看图讲故事
Attack and defense world ----- summary of web knowledge points
idea 2021中文乱码
【统计学习方法】学习笔记——提升方法
Review and arrangement of HCIA
牛客网刷题网址
File upload vulnerability - upload labs (1~2)
Niuke website