Loading... 基于经常需要分析一大段报文,因此对101/104报文解析做了个修正,支持多条依次解析。 同时加上了101/104报文的短帧解析。 # 一.多帧报文依次解析 ```c++ /// <summary> /// 规约解析 /// </summary> void CProtocolToolDlg::OnBnClickedButton1() { try { /*获取字节长度配置信息*/ uint8_t linkAddrLen = 2, asduLen = 2, cotLen = 2, infoAddrLen = 2, balancedMode = 0; linkAddrLen = ((CComboBox*)GetDlgItem(IDC_CMB_LINKADDRLEN))->GetCurSel() + 1; asduLen = ((CComboBox*)GetDlgItem(IDC_CMB_ASDULEN))->GetCurSel() + 1; cotLen = ((CComboBox*)GetDlgItem(IDC_CMB_COTLEN))->GetCurSel() + 1; infoAddrLen = ((CComboBox*)GetDlgItem(IDC_CMB_INFOADDRLEN))->GetCurSel() + 1; balancedMode = ((CComboBox*)GetDlgItem(IDC_CMB_BALANCEMODE))->GetCurSel(); CString text; GetDlgItemText(IDC_EDIT_Protocol, text); if (text.IsEmpty()) { MessageBox("请输入十六进制文本字符串后再试!", "提示"); return; } /*十六进制报文文本处理*/ text.Replace(" ", ""); text.Replace("0x", ""); text.Replace(",", ""); text.Replace("\n", ""); text.Replace("\r", ""); text.Replace("\t", ""); text.Replace(";", ""); if (text.Find("x") != -1) { MessageBox("包含非法字符'x'!", "提示"); return; } /*十六进制报文文本转 uint8_t[]*/ uint8_t* tmp = new uint8_t[text.GetLength()]; memset(tmp, 0, text.GetLength()); ByteHandler::Str2Hex(tmp, text.GetBuffer(), text.GetLength() / 2); text.ReleaseBuffer(); uint32_t startIndex = 0; //当前解析起始位置 uint8_t packetLen = 0; //当前报文长度 CAtlString text11; //解析文本 uint8_t* ptr_buffer = tmp; while (startIndex< text.GetLength() / 2) { /*报文解析类初始化*/ ProtocolCheck pCheck(ptr_buffer, text.GetLength() / 2-startIndex, linkAddrLen, asduLen, cotLen, infoAddrLen, balancedMode); /*判断是否为101/104报文*/ auto pType = pCheck.IsDL10xPacket(packetLen); if (pType != 1 && pType != 2) { /*未找到一条完整报文*/ SetDlgItemText(IDC_EDIT_Protocol_Result, "非101/104格式报文"); break; } /*控制字、传送原因、公告地址和类型标志解析*/ char str_ctrl[64] = { 0 }, str_cot[64] = { 0 }, str_asdu[64] = { 0 }, str_ti[64] = { 0 }; auto ctrl = pCheck.GetCtrlWord(str_ctrl); auto cot = pCheck.GetCotWord(str_cot); auto asdu = pCheck.GetAsduWord(); auto ti = pCheck.GetTi(str_ti); /*单帧报文提取,并转换为 文本*/ char tmpStr[255 * 3 + 1] = { 0 }; ByteHandler::Hex2Str(tmpStr, &ptr_buffer[pCheck.GetIndex()], packetLen); if (pType == 2) text11.AppendFormat("单条报文:%s\r\n控 制 字:%d[%s]\r\n传送原因:%d[%s]\r\n公共地址:%d\r\n类型标志:%d[%s]\r\n", tmpStr, ctrl, str_ctrl, cot, str_cot, asdu, ti, str_ti); else text11.AppendFormat("单条报文:%s\r\n链路地址:%d\r\n控 制 字:%d[%s]\r\n传送原因:%d[%s]\r\n公共地址:%d\r\n类型标志:%d[%s]\r\n", tmpStr,packetLen<=6?0: pCheck.GetLinkAddr(), ctrl, str_ctrl, cot, str_cot, asdu, ti, str_ti); /*长帧,进行信息体解析*/ if (packetLen > 6) { auto infoData = pCheck.GetInfoDataNum(); for (int i = 0; i < infoData.size(); i++) { text11.AppendFormat("0x%X:%s %s\t", infoData.at(i).Address, infoData.at(i).Data.c_str(), infoData.at(i).TimeStamp.c_str()); if (i == infoData.size() - 1) text11.Append("\r\n"); } } text11.Append("\r\n"); /*获取新的起始地址*/ startIndex += pCheck.GetIndex()+ packetLen; ptr_buffer = &tmp[startIndex]; } SetDlgItemText(IDC_EDIT_Protocol_Result, text11); delete[] tmp; } catch (...) { SetDlgItemText(IDC_EDIT_Protocol_Result, "解析失败"); } } ``` # 二.短帧识别及解析 ```c++ if (uBuffer[uIndex] == 0x10 && uIndex + 3 + uAsduLen < uLen) //101短帧 头部识别 { if (uBuffer[uIndex + 3 + uAsduLen] == 0x16 && ByteHandler::CalcSum(&uBuffer[uIndex + 1], 1 + uAsduLen) == uBuffer[2 + uAsduLen])//101短帧尾部识别及校验位判断 { ret = 1; len = 4 + uAsduLen; break; } } ``` 控制字解析: ```c++ uint32_t ProtocolCheck::GetCtrlWord(char* descript) { uint32_t ctrl = 0; if (uType != 1 && uType != 2 ) return ctrl; if (uType == 1) //101报文 { if (uPacketLen > 6) { ctrl = uBuffer[uIndex + 4]; } else { ctrl = uBuffer[uIndex + 1]; } if (descript != nullptr) { auto res = GetBalancedCtrl(ctrl); strcpy(descript, res.c_str()); } } else { //104报文 memcpy(&ctrl, &uBuffer[uIndex + 2], 4); if (uPacketLen > 6) { if (descript != nullptr) { uint16_t ns = 0, nr = 0; memcpy(&ns, &uBuffer[uIndex + 2], 2); memcpy(&nr, &uBuffer[uIndex + 4], 2); sprintf(descript, "发送序列号:%d,接收序列号:%d", ns / 2, nr / 2); } } else { if ((uBuffer[2] & 0x03) == 0x01)//S帧 { uint16_t nr = ((*(uint16_t*)(&uBuffer[4])) >> 1) & 0x7fff;; sprintf(descript, "S帧,确认序列号:%d", nr ); } else//U帧 { bool STARTDT_ACT = (uBuffer[2] & 0x04) == 0x04 ? true : false; bool STARTDT_CON = (uBuffer[2] & 0x08) == 0x08 ? true : false; bool STOPDT_ACT = (uBuffer[2] & 0x10) == 0x10 ? true : false; bool STOPDT_CON = (uBuffer[2] & 0x20) == 0x20 ? true : false; bool TESTFR_ACT = (uBuffer[2] & 0x40) == 0x40 ? true : false; bool TESTFR_CON = (uBuffer[2] & 0x80) == 0x80 ? true : false; if (STARTDT_ACT) { strcpy(descript, "初始化链路"); } if (STARTDT_CON) { strcpy(descript, "初始化链路确认"); } if (STOPDT_ACT) { strcpy(descript, "结束链路"); } if (STOPDT_CON) { strcpy(descript, "结束链路确认"); } if (TESTFR_ACT) { strcpy(descript, "测试链路"); } if (TESTFR_CON) { strcpy(descript, "测试链路确认"); } } } } return ctrl; } std::string ProtocolCheck::GetBalancedCtrl(uint8_t ctrl) { char strCtrl[64] = { 0 }; auto fc = ctrl & 0xf; auto prm = (ctrl >> 6) & 0x1; char descript[64] = { 0 }; if (uBalancedMode == 0) //平衡模式 { if ((ctrl >> 7) == 0x1) //上行 { sprintf(strCtrl, "DIR:%d,PRM:%d,RES:%d,DFC:%d", (int)(ctrl >> 7) & 0x1, prm, (int)(ctrl >> 5) & 0x1, (int)(ctrl >> 4 & 0x1)); } else { sprintf(strCtrl, "DIR:%d,PRM:%d,FCB:%d,FCV:%d", (int)(ctrl >> 7) & 0x1, prm, (int)(ctrl >> 5) & 0x1, (int)(ctrl >> 4 & 0x1)); } } else //非平衡模式 { sprintf(strCtrl, "RES:%d,PRM:%d,FCB/ACD:%d,FCV/DFC:%d", (int)(ctrl >> 7) & 0x1, prm, (int)(ctrl >> 5) & 0x1, (int)(ctrl >> 4 & 0x1)); } if (uBalancedMode == 0) //平衡模式 { if (prm == 1) //启动站 { switch (fc) { case 0: sprintf(descript, "%s,FC:复位远方链路",strCtrl); break; case 2: sprintf(descript, "%s,FC:发送/确认 链路测试功能", strCtrl); break; case 3: sprintf(descript, "%s,FC:发送/确认用户数据", strCtrl); break; case 4: sprintf(descript, "%s,FC:发送/无回答用户数据", strCtrl); break; case 9: sprintf(descript, "%s,FC:请求/响应 请求链路状态", strCtrl); break; default: sprintf(descript, "%s,FC:未知功能码", strCtrl); break; } } else //从动站 { switch (fc) { case 0: sprintf(descript, "%s,FC:确认: 认可", strCtrl); break; case 1: sprintf(descript, "%s,FC:确认: 否定认可", strCtrl); break; case 11: sprintf(descript, "%s,FC:响应: 链路状态", strCtrl); break; default: sprintf(descript, "%s,FC:未知功能码", strCtrl); break; } } } else //非平衡模式 { if (prm == 1) //启动站 { switch (fc) { case 0: sprintf(descript, "%s,FC:复位远方链路", strCtrl); break; case 3: sprintf(descript, "%s,FC:发送/确认用户数据", strCtrl); break; case 4: sprintf(descript, "%s,FC:发送/无回答用户数据", strCtrl); break; case 8: sprintf(descript, "%s,FC:访问请求", strCtrl); break; case 9: sprintf(descript, "%s,FC:请求/响应 请求链路状态", strCtrl); break; case 10: sprintf(descript, "%s,FC:请求/响应 请求1级用户数据", strCtrl); break; case 11: sprintf(descript, "%s,FC:请求/响应 请求2级用户数据", strCtrl); break; default: sprintf(descript, "%s,FC:未知功能码", strCtrl); break; } } else //从动站 { switch (fc) { case 0: sprintf(descript, "%s,FC:确认: 认可", strCtrl); break; case 1: sprintf(descript, "%s,FC:否定认可请求", strCtrl); break; case 8: sprintf(descript, "%s,FC:用户数据", strCtrl); break; case 9: sprintf(descript, "%s,FC:无所请求的用户数据", strCtrl); break; case 11: sprintf(descript, "%s,FC:请求/响应 请求2级用户数据", strCtrl); break; default: sprintf(descript, "%s,FC:未知功能码", strCtrl); break; } } } return std::string(descript); } ``` # 三.效果   最后修改:2022 年 05 月 04 日 10 : 26 PM © 允许规范转载