当前位置:网站首页>通讯协议设计与实现
通讯协议设计与实现
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;
}
边栏推荐
- Utiliser la pile pour convertir le binaire en décimal
- Idea 2021 Chinese garbled code
- Typescript interface inheritance
- 静态Vxlan 配置
- TypeScript 接口继承
- DOM parsing XML error: content is not allowed in Prolog
- In the small skin panel, use CMD to enter the MySQL command, including the MySQL error unknown variable 'secure_ file_ Priv 'solution (super detailed)
- SQL Lab (46~53) (continuous update later) order by injection
- Upgrade from a tool to a solution, and the new site with praise points to new value
- 千人规模互联网公司研发效能成功之路
猜你喜欢
Static comprehensive experiment
【统计学习方法】学习笔记——支持向量机(上)
Idea 2021 Chinese garbled code
【PyTorch实战】图像描述——让神经网络看图讲故事
[statistical learning methods] learning notes - improvement methods
Zhimei creative website exercise
wallys/Qualcomm IPQ8072A networking SBC supports dual 10GbE, WiFi 6
Static routing assignment of network reachable and telent connections
Problem: the string and characters are typed successively, and the results conflict
《看完就懂系列》天哪!搞懂节流与防抖竟简单如斯~
随机推荐
[statistical learning methods] learning notes - improvement methods
Static vxlan configuration
Sign up now | oar hacker marathon phase III midsummer debut, waiting for you to challenge
什么是ESP/MSR 分区,如何建立ESP/MSR 分区
Up meta - Web3.0 world innovative meta universe financial agreement
数据库系统原理与应用教程(011)—— 关系数据库
leetcode刷题:二叉树27(删除二叉搜索树中的节点)
Static comprehensive experiment
Object. Simple implementation of assign()
MPLS experiment
Is it safe to open Huatai's account in kainiu in 2022?
SQL blind injection (WEB penetration)
Will the filing free server affect the ranking and weight of the website?
Baidu digital person Du Xiaoxiao responded to netizens' shouts online to meet the Shanghai college entrance examination English composition
Experiment with a web server that configures its own content
【PyTorch实战】用PyTorch实现基于神经网络的图像风格迁移
AirServer自动接收多画面投屏或者跨设备投屏
Error in compiling libssl
千人规模互联网公司研发效能成功之路
Xiaohongshu microservice framework and governance and other cloud native business architecture evolution cases