- 📚 相关推荐文章
- crc校验码 推荐
- crc算法 推荐
- 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; }