1 设计基础
这里指的协议是应用层协议,针对应用协议的设计,需要注意的有几个基本点:可识别,兼容性,访问控制,可追溯,数据完整性校验。
首先是可识别,一般我们采用一个帧头来表示整个报文的起始位置,这个帧头可以用一个32位(uint32_t)的数值来标识,比如 0xFE01A0BC,大端序是 0xFE,0x01,0xA0,0xBC;
通常我们把这个数值称为魔数,magic number。
然后是兼容性,一般我们用一个字节来标识报文的版本号,这个版本号的作用是以后协议格式发生改变时,可以上下兼容;我们称这个字节标识为:revision;兼容的方式在应用逻辑上可以是这样的:上位机检查下位机的revision,协商一个两边都能解析处理的版本进行数据处理。
访问控制可以使用1个字节(uint8_t)或者2个字节(uint16_t),称为access control;数据的组织格式可以采用独热码的方式,也就是每个位表示一种标识,1个字节(8个位)最多8种标识,2个字节(16位)最多16种标识。比如0x0100表示同步帧,0x1000表示需要响应,那么0x0100 | 0x1000就标识这个帧是同步帧,而且需要响应。我们可以利用访问控制来做分包传输的逻辑。
可追溯一般指下发的报文和响应的报文要能够对得上,于是需要在每个报文中带上一个序列码,称为sequence number;可以是1到2个字节,每次传输都采用自加的方式,当报文需要响应时,响应报文的序列码保持一致。
接着就是用户数据了,一般采用2个字节(最多65535)来表示数据长度,紧接着是用户数据,也称为payload。
数据完整性校验可以采用CRC16的计算方式,需要2个字节;计算从包头到payload的结尾进行CRC16的运算,用来保证数据的完整性(没有发生篡改或者误码情况)。
2 协议格式
基于上述的出发点,我们可以把协议定义如下:
起始码 |
revision |
访问控制 |
序列码 |
数据长度 |
用户数据 |
CRC16 |
4 bytes |
1 byte |
2 bytes |
1 byte |
2 bytes |
—— |
2 bytes |