0.前言
最近项目中用到了单表数据远程上穿的需求,用的是《水资源检测数据传输规约——SZY206-2016》这个协议,研究了几天,里面很多都是针对数据的位做解析,经常对一个byte的8个位都做了不同的定义,感觉很有意思。本案例需要对照SZY206-2016协议来学习,网上到处都有下载的。
1.帧结构
协议主要分为如图所示几大部分,其中用户数据区域为用户自定义的一些数据,一般包含控制域和地址域,也有特殊情况,比如说在命令回复帧就不一定包含数据地址域,所以在针对CS校验时,针对整个用户数据区进行校验。
此协议包含控制指令,数据上传指令,时间指令,密码指令等众多指令,所以很难开发出一个可以兼容所有指令的类,本着可拓展的原则,这里定义了ICmd接口,数据解析业务由继承该接口的类进行具体实现。
现在主要的业务就是上传水质监测数据,暂时不涉及反控指令,也就实现了数据整体组帧SZY206Command,时间组帧TpCmd,WaterFactorCmd因子组帧,后续反控等其他业务有需要再实现。
2.CRC校验
以前也用过CRC校验,感觉CRC校验应该有一个统一的算法。经过这个项目发现,CRC校验也是有不同的算法实现的CRC8、CRC16、CRC32等不同校验长度,另外还有不同的校验算法。我这里的校验算法是x7+x6+x5+x2+1,也就是CRC8校验,转化为二进制为11100101,16进制为0xE5。校验算法再代码中已经给出。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CRC
{
public class Crc8
{
private readonly byte[] table = new byte[256];
public byte ComputeChecksum(byte[] bytes)
{
byte crc = 0;
if (bytes != null && bytes.Length > 0)
{
foreach (byte b in bytes)
{
crc = table[crc ^ b];
}
}
return crc;
}
public Crc8(byte poly)
{
for (int i = 0; i < 256; ++i)
{
int temp = i;
for (int j = 0; j < 8; ++j)
{
if ((temp & 0x80) != 0)
{
temp = (temp << 1) ^ poly;
}
else
{
temp <<= 1;
}
}
table[i] = (byte)temp;
}
}
}
}
3.标准帧解析示例
现在以一个水站数据传输帧进行解析,达到快速学习此协议目的。
发送:68 19 68 BA 0 62 39 E1 0 C0 80 0 0 0 0 0 0 0 0 0 0 0 0 17 41 11 12 0 92 16
接收:68 3 68 3A C0 0 A5 16
1.标志颜色的分别为控制域,B为1011,解析规则看下表,A为10,查表的为水质参数。
2.0 62 39 E1 0 为地址域,这里地址域按第二种方式解析,一般由对接平台直接给出。
3.C0 80 0 0 0 0 0 0 0 0 0 0 0 0 17 41 11 12 0为数据域,这里上传的为一个水温参数,第一位的C0为AFN码, 80 0 0 0 0为40个水质状态码,可以解析为40个bool量,后面分别为上传数据,机器状态码,时间码
4.后面92为校验码,16为结束符。