#include #include #include #include #include #include #include #include #include "client2.h" #include // 辅助转换函数 float IntToFloat(int num) { return static_cast(num) / 65536.0f; } float ShorToFloat100(short num) { return static_cast(num) / 100.0f; } float ShorToFloat1000(short num) { return static_cast(num) / 1000.0f; } float ShorToFloat10000(short num) { return static_cast(num) / 10000.0f; } // 字节序转换函数 void ReversalBuff(uint8_t* buff, int start, int length) { for (int i = 0; i < length / 2; i++) { std::swap(buff[start + i], buff[start + length - 1 - i]); } } // 辅助函数:解析MAC地址并填充到缓冲区 //lnk20250808 static inline int hex_nibble(char c) { if (c >= '0' && c <= '9') return c - '0'; c = static_cast(std::tolower(static_cast(c))); if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); return -1; } // 安全版:不抛异常,返回 true/false bool GetMAC(const std::string& strMAC, std::vector& packet, size_t startIndex, std::string* err = nullptr) { // 1) 规范化:去掉 '-', ':', ' ' std::string s; s.reserve(strMAC.size()); for (char c : strMAC) { if (c == '-' || c == ':' || c == ' ') continue; s.push_back(c); } // 2) 长度校验 if (s.size() != 12) { if (err) *err = "MAC长度必须为12个十六进制字符"; return false; } // 3) 十六进制校验 + 解析 std::array mac{}; for (int i = 0; i < 6; ++i) { int hi = hex_nibble(s[2*i]); int lo = hex_nibble(s[2*i + 1]); if (hi < 0 || lo < 0) { if (err) *err = "MAC含非法字符(必须是0-9或A-F)"; return false; } mac[i] = static_cast((hi << 4) | lo); } // 4) 确保缓冲区足够写入64字节(MAC 6字节 + 其后补零) const size_t need = startIndex + 64; if (packet.size() < need) packet.resize(need, 0); // 5) 写入MAC for (int i = 0; i < 6; ++i) { packet[startIndex + i] = mac[i]; } // 6) 其余位置补零(若 resize 过,这里基本已是0,但保证一下) for (size_t i = 6; i < 64; ++i) { packet[startIndex + i] = 0; } return true; } /*void GetMAC(const std::string& strMAC, std::vector& packet, size_t startIndex) { // 移除所有空格和短横线 std::string cleanedMAC = strMAC; cleanedMAC.erase(std::remove(cleanedMAC.begin(), cleanedMAC.end(), ' '), cleanedMAC.end()); cleanedMAC.erase(std::remove(cleanedMAC.begin(), cleanedMAC.end(), '-'), cleanedMAC.end()); // 验证长度 if (cleanedMAC.length() != 12) { throw std::invalid_argument("MAC地址长度必须为12个字符"); } try { // 解析每两个字符作为十六进制字节 for (int i = 0; i < 6; i++) { // 提取两个字符的子串 std::string byteStr = cleanedMAC.substr(i * 2, 2); // 转换为十六进制字节 unsigned char byte = static_cast( std::stoi(byteStr, nullptr, 16) ); // 填充到指定位置 if (startIndex + i < packet.size()) { packet[startIndex + i] = byte; } } // 剩余部分填0 (总共需要64字节,但MAC只占6字节) for (int i = 6; i < 64; i++) { if (startIndex + i < packet.size()) { packet[startIndex + i] = 0; } } } catch (const std::exception& e) { throw std::invalid_argument("无效的MAC地址: " + std::string(e.what())); } }*/ // CRC计算函数 unsigned char GetCrcSum(const std::vector& Check, int nOffset, int nLen) { unsigned char reg_b = 0x00; for (int i = 0; i < nLen; ++i) { if (static_cast(i + nOffset) >= Check.size()) { throw std::out_of_range("Index out of range in GetCrcSum"); } reg_b += Check[i + nOffset]; } return reg_b; } // 时间转换函数(TagMsTime -> 毫秒时间戳) uint64_t convertTagMsTimeToMsTimestamp(const TagMsTime& t) { struct tm tm_time = {}; tm_time.tm_year = t.Year - 1900; tm_time.tm_mon = t.Month - 1; tm_time.tm_mday = t.Day; tm_time.tm_hour = t.Hour; tm_time.tm_min = t.Min; tm_time.tm_sec = t.Sec; tm_time.tm_isdst = -1; // 自动判断夏令时 // 转换为时间戳(秒) time_t seconds = mktime(&tm_time); if (seconds == -1) return 0; // 加上毫秒 return static_cast(seconds) * 1000 + t.Ms; } // 解析日志生成QVVRRecord QVVRRecord DynamicLog_GetQVVRRecordFromLogBuffer( const std::string& strScale, uint32_t nPTType, float fPT, const NewTaglogbuffer& log) { QVVRRecord record; try { // 转换时间 record.triggerTimeMs = convertTagMsTimeToMsTimestamp(log.head.Devtime); // 提取参数 float fParam1 = 0.0f; // 持续时间 float fParam2 = 0.0f; // 特征幅值 float fParam3 = 0.0f; // 浮动门槛值 for (const auto& body : log.bodyList) { switch (body.ParaCode) { case 0: // 特征幅值(暂态单独使用) fParam2 = static_cast(body.ParaValue) / 65536.0f; break; case 1: // 持续时间(瞬态和暂态公用) fParam1 = static_cast(body.ParaValue) / 65536.0f; break; case 25: // 浮动门槛值(瞬态和暂态公用) fParam3 = static_cast(body.ParaValue) / 65536.0f; break; case 3: //电压幅度(瞬态单独使用) record.fMagntitude = (static_cast(body.ParaValue) / 65536.0f) / 100.0f; break; case 5: //相别(瞬态单独使用) record.phase = static_cast(body.ParaValue) / 65536.0f; break; case 6: //瞬变幅度(瞬态单独使用) record.transientValue = (static_cast(body.ParaValue) / 65536.0f) / 100.0f; break; default: break; } } record.fPersisstime = fParam1; // 计算基准值fBase float fBase = 0.0f; if (fParam3 < 50.0f) { // 未上送浮动门槛 if (fPT != 1.0f) { // 变比不为1 fBase = (nPTType == 0) ? 57.74f : 100.0f; } else { std::string strTemp = strScale; std::transform(strTemp.begin(), strTemp.end(), strTemp.begin(), ::tolower); size_t pos = strTemp.find('k'); if (pos != std::string::npos) { std::string numPart = strTemp.substr(0, pos); try { float fTemp = std::stof(numPart) * 1000.0f; fBase = (nPTType == 0) ? (fTemp / std::sqrt(3.0f)) : fTemp; } catch (...) { fBase = (nPTType == 0) ? 57.74f : 100.0f; } } else { fBase = (nPTType == 0) ? 57.74f : 100.0f; } } } else { fBase = fParam3; // 使用浮动门槛值 } // 设置事件类型 switch (log.head.LogCode) { case 0: case 26: case 40: case 54: case 68: case 82: record.nType = 3; break; case 1: case 27: case 41: case 55: case 69: case 83: record.nType = 1; break; case 13: case 36: case 50: case 64: case 78: case 92: record.nType = 2; break; case 24: // 手动启动录波,保持默认类型0 break; case 100: record.nType = 1; // 模拟电压暂降 break; case 3: record.nType = 4; // 瞬态事件 default: // 未知类型保持0 break; } // 特殊处理:中断事件且幅值较大 if (record.nType == 3 && fParam2 > fBase * 0.1f) { fParam2 /= 100.0f; } // 计算特征幅值(标幺值) record.fMagntitude = fParam2 / fBase; } catch (...) { // 异常时返回空记录 record = QVVRRecord{}; } return record; } // 主函数:组装二进制报文 std::vector GetMsg(const std::vector& SrcData, unsigned char nType) { // 参数检查 if (SrcData.empty() || ((nType < 0x01 || nType > 0xA4) && nType != 0xFF)) { return {}; } try { // 计算总长度:报文头(6) + 额外字段(2) + 功能码(1) + 数据体 + CRC+结束符(2) const size_t total_len = 6 + 2 + 1 + SrcData.size() + 2; std::vector msg(total_len); // 组装报文头 (6字节) msg[0] = 0xEB; // 报文头 msg[1] = 0x90; // 报文头 msg[2] = 0x00; // 备用 msg[3] = 0x00; // 备用 // 设置长度字段(数据体长度+功能码) uint16_t data_len = static_cast(SrcData.size() + 1); msg[4] = static_cast(data_len >> 8); // 长度高字节 msg[5] = static_cast(data_len & 0xFF); // 长度低字节 // 额外字段 (2字节) msg[6] = 0x00; // 备用 msg[7] = 0xFF; // 备用 // 功能码 msg[8] = nType; // 复制数据体 if (!SrcData.empty()) { std::copy(SrcData.begin(), SrcData.end(), msg.begin() + 9); } // 计算CRC(从索引8开始,长度 = 功能码+数据体) unsigned char crc = GetCrcSum(msg, 8, 1 + SrcData.size()); msg[msg.size() - 2] = crc; msg[msg.size() - 1] = 0x16; // 结束符 return msg; } catch (const std::exception& ex) { throw std::runtime_error(std::string("Exception in GetMsg: ") + ex.what()); } catch (...) { throw std::runtime_error("Unknown exception in GetMsg"); } } // 生成装置云服务登录报文 std::vector generate_frontlogin_message(const std::string& strMac) { const size_t packetSize = 150; // 报文总长150 数据体+帧序号140 std::vector packet(packetSize, 0); // 初始化为全0 // 协议头 packet[0] = 0xEB; // 起始标志1 packet[1] = 0x90; packet[2] = 0xEB; // 起始标志2 packet[3] = 0x90; packet[4] = 0x8C; // 数据体长度 (140 = 0x008C) packet[5] = 0x00; // [6-7] 随机码 (保持为0) // [8-9] 功能码 (保持为0) // [10-11] 帧序号 (保持为0) // 数据体1 packet[12] = 'F'; packet[13] = 'T'; packet[14] = 'I'; packet[15] = 'D'; // [16-19] 数据体2 (保持为0) // 填充MAC地址 (从位置20开始,64字节) //GetMAC(strMac, packet, 20); //lnk20250808 std::string err; if (!GetMAC(strMac, packet, 20, &err)) { std::cerr << "[GetMAC] parse failed: " << err << "\n"; // 做降级或返回 } // 计算校验和 (从偏移8到137) unsigned char checksum = 0; for (size_t i = 8; i < packetSize - 2; i++) { checksum += packet[i]; } packet[packetSize - 2] = checksum; // 结束符 packet[packetSize - 1] = 0x16; //lnk20250808 // ======= 调试输出报文 ======= std::cout << "[generate_frontlogin_message] Packet (" << packet.size() << " bytes):\n"; for (size_t i = 0; i < packet.size(); ++i) { printf("%02X ", packet[i]); if ((i + 1) % 16 == 0) printf("\n"); } if (packet.size() % 16 != 0) printf("\n"); return packet; } //询问统计数据时间报文 std::vector generate_statequerytime_message() { // 创建2字节数据缓冲区(初始化为0) std::vector DataBuf(2, 0x00); // 调用GetMsg生成完整报文 return GetMsg(DataBuf, static_cast(MsgRequestType::Request_StatTime)); } //询问统计数据报文 std::vector generate_statequerystat_message(tagTime time, uint16_t nDeviceNo, uint16_t nDataType) { // 计算总大小:3(备用) + 2(nDeviceNo) + 2(nDataType) + time结构大小 const size_t totalSize = 3 + 2 * sizeof(uint16_t) + time.GetSize(); std::vector DataBuf(totalSize, 0x00); // 初始化为全0 size_t offset = 0; // 1. 跳过3字节备用区(已初始化为0) offset += 3; // 2. 写入nDeviceNo(网络字节序) uint16_t netDeviceNo = htons(nDeviceNo); memcpy(DataBuf.data() + offset, &netDeviceNo, sizeof(uint16_t)); offset += sizeof(uint16_t); // 3. 写入nDataType(网络字节序) uint16_t netDataType = htons(nDataType); memcpy(DataBuf.data() + offset, &netDataType, sizeof(uint16_t)); offset += sizeof(uint16_t); // 4. 写入time结构(内部已处理网络字节序) time.GetStructBuf(DataBuf.data(), DataBuf.size(), offset); // 生成完整报文 return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Stat)); } //询问实时数据报文 测点1-6 数据类型1-11 谐波次数0-2 std::vector generate_realstat_message(unsigned char nCpuNo, unsigned char StaTtype, unsigned char flag) { // 计算总大小:3(备用) + 1(nCpuNo) + 1(StaTtype) + 1(固定值) + 1(flag) const size_t totalSize = 7; std::vector DataBuf(totalSize, 0x00); // 初始化为全0 size_t offset = 0; // 1. 跳过3字节备用区(已初始化为0) offset += 3; // 2. 写入nCpuNo(1字节) 监测点序号 1-6 memcpy(DataBuf.data() + offset, &nCpuNo, sizeof(unsigned char)); offset += sizeof(unsigned char); // 3. 写入StaTtype(1字节) 数据类型 1-11 一般仅读 1-6 memcpy(DataBuf.data() + offset, &StaTtype, sizeof(unsigned char)); offset += sizeof(unsigned char); // 4. 写入固定值1(1字节) 3秒实时数据仅有1 表示平均值 const unsigned char fixedValue = 1; memcpy(DataBuf.data() + offset, &fixedValue, sizeof(unsigned char)); offset += sizeof(unsigned char); // 5. 写入flag(1字节) 标志位 0-2 谐波次数 25 50 100次 memcpy(DataBuf.data() + offset, &flag, sizeof(unsigned char)); // 生成完整报文 return GetMsg(DataBuf, static_cast(MsgRequestType::Request_New_3S)); } // 生成文件下载请求报文 当前帧序号+文件名 std::vector generate_downloadfile_message(int frameIndex, const std::string& fileName) { // 数据体大小: 3(备用) + 4(帧序号) + 128(文件名) = 135字节 std::vector dataBuf(135, 0x00); // 写入帧序号 (4字节,大端序) //uint32_t netFrameIndex = htonl(static_cast(frameIndex)); //memcpy(dataBuf.data() + 3, &netFrameIndex, sizeof(uint32_t)); // 移除htonl转换,直接使用原始帧序号(小端序) uint32_t rawFrameIndex = static_cast(frameIndex); memcpy(dataBuf.data() + 3, &rawFrameIndex, sizeof(uint32_t)); // 写入文件名 (最多128字节) size_t copyLen = std::min(fileName.size(), static_cast(128)); if (copyLen > 0) { memcpy(dataBuf.data() + 7, fileName.c_str(), copyLen); } // 调用GetMsg生成完整报文 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_File_Download)); } //文件目录读取报文 传入需要读取的文件路径 std::vector generate_getfilemenu_message(const std::string& filedir) { // 创建固定131字节缓冲区 (3 + 128),初始化为0 std::vector dataBuf(131, 0x00); // 复制文件名到缓冲区(偏移量3开始) size_t copyLen = std::min(filedir.size(), static_cast(128)); if (copyLen > 0) { memcpy(dataBuf.data() + 3, filedir.c_str(), copyLen); } // 调用GetMsg生成完整报文 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_FileDir)); } // 请求定值报文 传入测点号 std::vector generate_requestFixValue_message(unsigned char nCpuNo) { // 参数检查 if (nCpuNo < 1 || nCpuNo > 6) return std::vector(); // 创建4字节缓冲区并初始化 std::vector DataBuf(4, 0x00); DataBuf[3] = nCpuNo; // CPU编号放在第4字节 // 生成完整报文 return GetMsg(DataBuf, static_cast(MsgRequestType::Request_FixValue)); } // 请求定值描述报文 std::vector generate_requestFixDes_message() { // 创建3字节缓冲区并初始化 std::vector DataBuf(3, 0x00); // 生成完整报文 return GetMsg(DataBuf, static_cast(MsgRequestType::Request_FixDes)); } // 设置定值报文 传入测点号+修改的定值数据队列 std::vector generate_requestSetFixValue_message( unsigned char nCpuNo, const std::vector& value) { // 参数检查 if (nCpuNo < 1 || nCpuNo > 6) return std::vector(); // 计算缓冲区大小: 4(头部) + 浮点数组长度*4 const size_t bufSize = 4 + value.size() * 4; std::vector DataBuf(bufSize, 0x00); DataBuf[3] = nCpuNo; // CPU编号放在第4字节 // 处理每个浮点值 for (size_t i = 0; i < value.size(); i++) { // 将float转换为网络字节序 uint32_t intValue; memcpy(&intValue, &value[i], sizeof(float)); uint32_t netValue = htonl(intValue); // 将转换后的值复制到缓冲区 unsigned char* dest = DataBuf.data() + 4 + i * 4; memcpy(dest, &netValue, sizeof(uint32_t)); } // 生成完整报文 return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Set_Fix)); } /** * @brief 生成请求装置内部定值的报文 * @return 包含完整报文的字节向量 */ std::vector generate_requestinterfixvalue_message() { // 创建3字节数据缓冲区并初始化为0 std::vector dataBuf(3, 0x00); // 调用通用报文生成函数 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Read_InterFix)); } /** * @brief 生成请求装置内部定值描述的报文 * @param nDesCW 描述类型 (1-内部定值描述, 2-控制字描述) * @return 包含完整报文的字节向量,参数无效时返回空向量 */ std::vector generate_requestinterfixdes_message(unsigned char nDesCW) { // 参数有效性检查 if (nDesCW < 1 || nDesCW > 2) { return std::vector(); } // 创建3字节数据缓冲区 std::vector dataBuf(3, 0x00); // 设置描述类型 dataBuf[0] = nDesCW; // 调用通用报文生成函数 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Read_InterFixDes)); } /** * @brief 生成设置装置内部定值的报文 * @param values 要设置的定值数组 (ushort值) * @return 包含完整报文的字节向量 */ std::vector generate_requestsetinterfixvalue_message(const std::vector& values) { // 计算缓冲区大小: 3字节头部 + 每个值占2字节 const size_t bufSize = 3 + values.size() * 2; std::vector dataBuf(bufSize, 0x00); // 填充定值数据 for (size_t i = 0; i < values.size(); i++) { // 将ushort值转换为网络字节序 (大端) uint16_t netValue = htons(values[i]); // 计算目标位置偏移量 (跳过3字节头部) unsigned char* dest = dataBuf.data() + 3 + i * 2; // 复制转换后的值到缓冲区 memcpy(dest, &netValue, sizeof(uint16_t)); } // 调用通用报文生成函数 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Set_InterFix)); } /** * @brief 生成设置装置内部定值的报文 * @param values 要设置的定值数组 (ushort值) * @return 包含完整报文的字节向量 */ std::vector generate_requestsetinterfixvalue_message_new(const std::vector& value) { // 计算缓冲区大小: 3字节头部 + 每个值占2字节 const size_t bufSize = 3 + value.size() * 2; std::vector dataBuf(bufSize, 0x00); // 填充定值数据 for (size_t i = 0; i < value.size(); i++) { // 将值转换为字节数组 uint16_t rawValue = value[i]; unsigned char* bytes = reinterpret_cast(&rawValue); // 反转字节序(模拟C#的ReversalBuff) std::swap(bytes[0], bytes[1]); // 计算目标位置偏移量 (跳过3字节头部) unsigned char* dest = dataBuf.data() + 3 + i * 2; // 复制转换后的值到缓冲区 memcpy(dest, bytes, sizeof(uint16_t)); } // 调用通用报文生成函数 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Set_InterFix)); } /** * @brief 生成装置运行信息读取指令报文 * @return 包含完整报文的字节向量 */ std::vector generate_machinestatus_message() { // 创建10字节数据缓冲区,初始化为0 std::vector DataBuf(10, 0x00); // 设置索引3的值为1(第4个字节) DataBuf[3] = 0x01; // 调用通用报文生成函数,功能码14对应装置状态读取 return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Read_RunningInformation)); } /** * @brief 生成装置版本配置信息读取指令报文 * @return 包含完整报文的字节向量 */ std::vector generate_machineversion_message() { // 创建10字节数据缓冲区,初始化为0 std::vector DataBuf(10, 0x00); // 设置索引3的值为1(第4个字节) DataBuf[3] = 0x02; // 调用通用报文生成函数,功能码14对应装置状态读取 return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Read_RunningInformation)); }