Loading... # 101/104报文解析の起步 代码仓库:[灯火微抹/WorkEasierTooler - 码云 - 开源中国 (gitee.com)](https://gitee.com/dhwm/work-easier-tooler/tree/DevOps) ## 类结构 为了更便捷、傻瓜式使用,采用模糊方式,自动匹配101或104规约,自动匹配链路地址长度、传送原因长度和ASDU公共地址长度。 信息体对象结构体定义: ```c++ struct InfoData { uint32_t Address; //地址 float Data; //值 std::string date; //时间戳 }; ``` 101/104报文解析类定义: ```c++ class ProtocolCheck { public: ProtocolCheck(uint8_t* buf,uint16_t len); ~ProtocolCheck(); /// <summary> /// 判断是否为101/104报文,忽略短帧 /// </summary> /// <returns>1:101,2:104,-1:校验和错,-2:非101/104报文</returns> int IsDL10xPacket(uint8_t& len); /// <summary> /// 获取控制字 /// </summary> /// <param name="descript">控制字解析,为空时无</param> /// <returns></returns> uint8_t GetCtrlWord(char* descript=nullptr); /// <summary> /// 获取链路地址 /// </summary> /// <param name="len">链路地址字节长度</param> /// <param name="descript">控制字解析,为空时无</param> /// <returns></returns> uint16_t GetLinkAddr(uint8_t& len, char* descript = nullptr); /// <summary> /// 获取传送原因 /// </summary> /// <param name="len">传送原因字节长度</param> /// <param name="descript">传送原因解析,为空时无</param> /// <returns></returns> uint16_t GetCotWord(uint8_t& len, char* descript = nullptr); /// <summary> /// 获取公共地址 /// </summary> /// <param name="len">公共地址字节长度</param> /// <param name="descript">公共地址解析,为空时无</param> /// <returns></returns> uint16_t GetAsduWord(uint8_t& len, char* descript = nullptr); /// <summary> /// 获取类型标志 /// </summary> /// <param name="descript">类型标志解析,为空时无</param> /// <returns></returns> uint8_t GetTi(char* descript = nullptr); /// <summary> /// 获取信息体数目 /// </summary> /// <param name="infoDatas">信息体对象</param> /// <returns></returns> uint8_t GetInfoDataNum(InfoData* infoDatas); private: uint8_t* uBuffer; uint16_t uLen; uint16_t uIndex; uint8_t uLinkAddrLen; uint8_t uCotLen; uint8_t uAsduLen; uint8_t uInfoAddrLen; }; ``` 是否是101/104报文判断: ```c++ int ProtocolCheck::IsDL10xPacket(uint8_t& len) { uIndex = 0; int ret = -2; while (uIndex < uLen) { //首字符应为0x68 if (uBuffer[uIndex] == 0x68 && uIndex+3<uLen)//报文首判断 { //检查是否满足101报文结构要求 uint8_t tmpLen = uBuffer[uIndex + 1]; //报文长度 if (tmpLen == uBuffer[uIndex + 2] && uBuffer[uIndex + 3] == 0x68) { //报文长度判断 if (uIndex + tmpLen + 6 <= uLen) { //结束字符判断 if (uBuffer[uIndex + tmpLen + 6 - 1] == 0x16) { //和校验判断 if (ByteHandler::CalcSum(&uBuffer[uIndex + 4], tmpLen) == uBuffer[uIndex + tmpLen + 6 - 2]) { ret = 1; } else { ret = -1; } len = tmpLen + 6; break; } } } //检查是否满足104报文结构要求 else if (uIndex + tmpLen + 6 <= uLen) { ret = 2; len = tmpLen + 2; break; } } uIndex++; } if (ret <= 0) return ret; //链路地址长度、传送原因长度、ASDU公共地址长度、信息体地址长度判断 uint32_t linkAddr = 0, cot = 0, asduAddr = 0, infoAddr = 0; uint8_t ti = 0; for (uint8_t a = 1; a <= 2; a++)//链路地址长度 { for (uint8_t b = 1; b <= 2; b++)//传送原因长度 { for (uint8_t c = 1; c <= 2; c++)//ASDU公共地址长度 { if (ret == 1) { //链路地址 linkAddr = ByteHandler::Hex2Dec(&uBuffer[uIndex + 5], a); //类型标志 ti = uBuffer[uIndex + 5 + a]; //传送原因 cot = ByteHandler::Hex2Dec(&uBuffer[uIndex + 7 + a], b); //ASDU公共地址 asduAddr = ByteHandler::Hex2Dec(&uBuffer[uIndex + 7 + a + b], c); } else if (ret == 2) { //类型标志 ti = uBuffer[uIndex + 6]; //传送原因 cot = ByteHandler::Hex2Dec(&uBuffer[uIndex + 8], b); //ASDU公共地址 asduAddr = ByteHandler::Hex2Dec(&uBuffer[uIndex + 8 + b], c); } //类型标志和传送原因可知 if (g_TI.contains(ti) && (g_Cot.contains(cot) || g_Cot.contains(0xf&cot))) { if (ret == 1) { uLinkAddrLen = a; } uCotLen = b; uAsduLen = c; break; } } } } //无法判断 if (ret == 1 && uLinkAddrLen == 0 || uCotLen == 0 || uAsduLen == 0) { uLinkAddrLen = 0; uCotLen = 0; uAsduLen = 0; ret = 0; } return ret; } ``` 最后修改:2022 年 05 月 04 日 10 : 26 PM © 允许规范转载