1.协议文档分析
对于嵌入式设备而言,每一个厂商或者公司来说,协议文档都是不一样的,所以具体的协议解析和组包在这里就不便说明,只记录一个基础框架:命令构造器、协议解析器、数据提取器(目前只写了这三个,后期再更新)
相对于我司而言,具体的通信协议帧格式如下:
帧头:2byte
帧长度:2byte
端口:1byte
指令类型:2byte
帧载荷:nbyte
校验和:1byte
帧尾:2byte
这些通讯协议数据的解析以及封装均为二进制,中间还采用了低字节序(LITTLE-ENDIAN)也就是小端模式,这里除了固定的帧头和帧尾外,其余部分均采用了小端模式
校验和:是指进行的CRC校验
还对数据帧中进行了特征字的定义,当出现特征字时就需要进行转义
2.数据提取器(FrameExtractor)
从串口接收到的数据,我们需要进行一些处理,因为避免无效的数据带来的影响,FrameExtractor是为了提取到一个符合规则正确的数据帧
2.1 初始化FrameExtractor
当从串口接收数据时,我们需要去建立一个缓冲区来存放接收到的数据
因为可能会发生以下几种情况:
1.串口当前接收到的数据不全,不是一个完整的数据帧
2.接收到了多个数据帧,当最后一个数据帧不是完整的
class FrameExtractor:
def __init__(self):
self.buffer = b''
self.frames = []
所以建立缓冲区来对数据进行处理:
1.当缓冲区数据不足一个完整的数据帧时,等待更多的数据到达
2.若有完整的数据帧,则提取出来
2.2 提取数据帧
对数据帧的提取,也就是解析,以下是解析的流程:
查找帧头--------->查找帧尾--------->进行校验和判断------->校验通过就行转义处理(还原原始数据)----->提取正确的数据帧
def extract_frames(self, data):
frames = []
frame_start_found = False # 新增标志变量,指示是否找到了帧头
# 将当前数据缓冲区中的数据与新接收到的数据合并
self.buffer +=data
start = None # 记录帧头的起始位置
# 处理数据缓冲区中的数据,提取完整的数据帧
while True:
# 如果缓冲区中的数据不足一个完整的数据帧,则退出循环等待更多数据到达
if len(self.buffer) < 6:
break
if not frame_start_found:
# 查找帧头
try:
start = self.buffer.index(b'\x5a\x55')
if start != None:
self.buffer = self.buffer[start:]
frame_start_found = True # 找到帧头,设置标志变量为True
continue
else:
frame_start_found = True # 找到帧头,设置标志变量为True
except ValueError as e:
self.buffer = []
print(f'error:{
e}')
break
else:
# 查找帧尾
try:
end