✅ 操作成功!

crc校验失败

发布时间:2023-06-11 作者:admin 来源:文学

crc校验失败

crc校验失败

-

2023年3月3日发(作者:杨秀青)

HJ212协议标准报⽂解析

HJ212分为2005年(HJ/T212-2005)和2017年(HJ212-2017)的版本,略有不同。

⽹上没找到⾮常官⽅的渠道下载,在这贴⼀份2017年版本的下载地址

TCP/IP通讯包组成

名称类型长度描述

包头字符2固定为

##数据段长度⼗进制整数4表⽰数据段长度,如长度336则为0336

数据段字符0-1024变长的数据,为包的传输内容

CRC校验⼗六进制整数4⽤于校验数据包完整性的CRC校验值,后续附上算法

包尾字符2固定为(回车、换⾏)

通讯包数据段组成

HJ/T212-2005

名称类型长度描述

请求编码QN字符20精确到毫秒的时间戳:QN=YYYYMMDDhhmmsszzz,⽤来唯⼀标识⼀次命令交互

系统编码ST字符5系统编号

命令编号CN字符7命令编号

访问密码PW字符6访问密码

设备唯⼀标识MN字符14监测点编号

拆分包及应答标志Flag字符3见⽂档原⽂

总包号PNUM字符4表⽰本次通讯总共包含的包数

包号PNO字符4PNO指⽰当前数据包的包号

指令参数CP字符0-960CP=&&数据区&&

HJ212-2017

名称类型长度描述

请求编码QN字符20精确到毫秒的时间戳:QN=YYYYMMDDhhmmsszzz,⽤来唯⼀标识⼀次命令交互

系统编码ST字符5系统编号

命令编号CN字符7命令编号

访问密码PW字符9访问密码

设备唯⼀标识MN字符27监测点编号

拆分包及应答标志Flag字符8见⽂档原⽂

总包号PNUM字符9表⽰本次通讯总共包含的包数

包号PNO字符8PNO指⽰当前数据包的包号

指令参数CP字符0-950CP=&&数据区&&

名称类型长度描述

报⽂解析

因2005、2017对原始报⽂的解析上没有什么巨⼤分别,只是不同字段的长度在2017协议中有所扩展。在此仅以⼀例2005年规范的报⽂作为样

例(因简书格式问题,调试时请⾃⾏补全包尾换⾏符):

"##0336ST=31;CN=2011;PW=123456;MN=63;CP=&&DataTime=25;B02-Rtd=9.88,B02-Flag=N;01-Rtd=10.73,01-ZsRtd=12.38,01-Flag=N;02

代码解析

在这⾥不赘述如何通过TCP/IP协议获得报⽂再转成字符串的了,直接贴⼀些关键代码(C#),直接看可能⽐看协议⽂档要快⼀些。

本来是想封装个类库的…不过考虑我实际使⽤情况只有最简单的接受解析数据,没调试过收发控制命令、数据分包。单纯根据⽂档封装出来可

能会有很⼤的局限性(其实是懒)。

因⼒求样例代码精简,可能缺乏防错及数据结构展现,⼤家可以针对⾃⼰实际业务需求做相应完善。

//Msg是解析TCP/IP报⽂后获得的报⽂字符串

if(OrEmpty(Msg)||<12||!With("##")||!th("rn"))

{

ine("不是HJ212协议的报⽂!");

returnfalse;

}

varmsg_len_str=ing(2,4);

if(!se(msg_len_str,outintmsg_len))

{

ine("报⽂格式⾮法,报⽂长度⽆法解析!");

returnfalse;

}

varcontent=ing(6,msg_len);

varmsg_crc=ing(6+msg_len,4);

varcalc_crc=CalcCRC(content);

if(calc_crc!=msg_crc)

{

ine($"CRC校验失败!MsgCRC:{msg_crc}CalcCRC:{calc_crc}");

returnfalse;

}

varcp=(content,@"CP=&&[S]*&&");

varmsg_head=;

if(!s)

{

ine("未匹配到数据!");

msg_head=content;

}

msg_head=ing(0,);

varheaders=msg_(';');

for(inti=0;i<-1;i++)

{

varindex=headers[i].IndexOf('=');

if(index==-1)continue;

ine($"Headerkey:{headers[i].Substring(0,index)}HeaderValue:{headers[i].Substring(index+1,headers[i].Length-index-1)}");

}

if(s)

{

vardatadic=ing(5,-7);

vardataarr=(';');

foreach(varrawdataindataarr)

{

varitems=(',');

foreach(varrawiteminitems)

{

varindex=f("=");

if(index==-1)

{

returnfalse;

}

ine($"DataName:{ing(0,index)}DataValue:{ing(index+1,-index-1)}");

}

}

}

returntrue;

针对以上报⽂的解析如下:

对于

DataName

的含义,参照协议⽂档中的字段对照表即可

B02-Rtd

代表废⽓-实时采样数据,不⼀定完全照搬⽂档,可与对接⼚商根据现场情况拟定。

CRC算法

CRC算法如下(摘⾃HJ212-2017,2005版本没有明确定义但实测是兼容的,语⾔是C):

⼀定要注意CRC是针对数据段进⾏计算的,去头(##、报⽂长度字符),去尾(CRC字符、包尾换⾏符)

unsignedintCRC16_Checkout(unsignedchar*puchMsg,unsignedintusDataLen)

{

unsignedinti,j,crc_reg,check;

crc_reg=0xFFFF;

for(i=0;i

{

crc_reg=(crc_reg>>8)^puchMsg[i];

for(j=0;j<8;j++)

{

check=crc_reg&0x0001;

crc_reg>>=1;

if(check==0x0001)

{

crc_reg^=0xA001;

}

}

}

returncrc_reg;

}

👁️ 阅读量:0