hj212协议如何和php通讯,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
字符
4
PNO指示當前數據包的包號
指令參數CP
字符
0-960
CP=&&數據區&&
HJ212-2017
名稱
類型
長度
描述
請求編碼QN
字符
20
精確到毫秒的時間戳:QN=YYYYMMDDhhmmsszzz,用來唯一標識一次命令交互
系統編碼ST
字符
5
系統編號
命令編號CN
字符
7
命令編號
訪問密碼PW
字符
9
訪問密碼
設備唯一標識MN
字符
27
監測點編號
拆分包及應答標志Flag
字符
8
見文檔原文
總包號PNUM
字符
9
表示本次通訊總共包含的包數
包號PNO
字符
8
PNO指示當前數據包的包號
指令參數CP
字符
0-950
CP=&&數據區&&
報文解析
因2005、2017對原始報文的解析上沒有什么巨大分別,只是不同字段的長度在2017協議中有所擴展。在此僅以一例2005年規范的報文作為樣例(因簡書格式問題,調試時請自行補全包尾換行符):
"##0336ST=31;CN=2011;PW=123456;MN=63010000020001;CP=&&DataTime=20200108143205;B02-Rtd=9.88,B02-Flag=N;01-Rtd=10.73,01-ZsRtd=12.38,01-Flag=N;02-Rtd=0.705,02-ZsRtd=0.814,02-Flag=N;03-Rtd=69.064,03-ZsRtd=79.684,03-Flag=N;S01-Rtd=5.8,S01-Flag=N;S02-Rtd=19.38,S02-Flag=N;S03-Rtd=99.04,S03-Flag=N;S08-Rtd=-46.12,S08-Flag=N;S05-Rtd=14.66,S05-Flag=N&&8EC1"
代碼解析
在這里不贅述如何通過TCP/IP協議獲得報文再轉成字符串的了,直接貼一些關鍵代碼(C#),直接看可能比看協議文檔要快一些。
本來是想封裝個類庫的…不過考慮我實際使用情況只有最簡單的接受解析數據,沒調試過收發控制命令、數據分包。單純根據文檔封裝出來可能會有很大的局限性(其實是懶)。
因力求樣例代碼精簡,可能缺乏防錯及數據結構展現,大家可以針對自己實際業務需求做相應完善。
//Msg 是解析TCP/IP報文后獲得的報文字符串
if (string.IsNullOrEmpty(Msg) || Msg.Length < 12 || !Msg.StartsWith("##") || !Msg.EndsWith("\r\n"))
{
Console.WriteLine("不是HJ212協議的報文!");
return false;
}
var msg_len_str = Msg.Substring(2, 4);
if (!int.TryParse(msg_len_str, out int msg_len))
{
Console.WriteLine("報文格式非法,報文長度無法解析!");
return false;
}
var content = Msg.Substring(6, msg_len);
var msg_crc = Msg.Substring(6 + msg_len, 4);
var calc_crc = CalcCRC(content);
if (calc_crc != msg_crc)
{
Console.WriteLine($"CRC校驗失敗! MsgCRC:{msg_crc} CalcCRC:{calc_crc}");
return false;
}
var cp = Regex.Match(content, @"CP=&&[\S]*&&");
var msg_head = string.Empty;
if (!cp.Success)
{
Console.WriteLine("未匹配到數據!");
msg_head = content;
}
msg_head = content.Substring(0, cp.Index);
var headers = msg_head.Split(';');
for (int i = 0; i < headers.Length - 1; i++)
{
var index = headers[i].IndexOf('=');
if (index == -1) continue;
Console.WriteLine($"Header key:{headers[i].Substring(0, index)} Header Value:{headers[i].Substring(index + 1, headers[i].Length - index - 1)}");
}
if (cp.Success)
{
var datadic = cp.Value.Substring(5, cp.Length - 7);
var dataarr = datadic.Split(';');
foreach (var rawdata in dataarr)
{
var items = rawdata.Split(',');
foreach (var rawitem in items)
{
var index = rawitem.IndexOf("=");
if (index == -1)
{
return false;
}
Console.WriteLine($"Data Name:{rawitem.Substring(0, index)} Data Value:{rawitem.Substring(index + 1, rawitem.Length - index - 1)}");
}
}
}
return true;
針對以上報文的解析如下:
對于Data Name的含義,參照協議文檔中的字段對照表即可
如B02-Rtd代表廢氣-實時采樣數據,不一定完全照搬文檔,可與對接廠商根據現場情況擬定。
CRC算法
CRC算法如下(摘自HJ212-2017,2005版本沒有明確定義但實測是兼容的,語言是C):
一定要注意CRC是針對數據段進行計算的,去頭(##、報文長度字符),去尾(CRC字符、包尾換行符)
unsigned int CRC16_Checkout(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned int i, j, crc_reg, check;
crc_reg = 0xFFFF;
for (i = 0; i < usDataLen; 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;
}
}
}
return crc_reg;
}
總結
以上是生活随笔為你收集整理的hj212协议如何和php通讯,HJ212数据传输标准报文解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 彩铃开发,motorola铃声
- 下一篇: PHP判断标量,php中is_scala