From 900569e5de97aa132ab2c1d3bddb81f0662990a4 Mon Sep 17 00:00:00 2001 From: zw <3466561528@qq.com> Date: Fri, 25 Jul 2025 10:47:50 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BA=86=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=B8=8E=E7=BB=9F=E8=AE=A1=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=9A=84=E8=BD=AC=E6=8D=A2=E6=96=B9=E5=BC=8F=E3=80=82=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E4=BA=86=E6=9A=82=E6=80=81=E4=BA=8B=E4=BB=B6=E4=B8=8E?= =?UTF-8?q?=E6=B3=A2=E5=BD=A2=E7=9A=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LFtid1056/PQSMsg.cpp | 154 +++++++ LFtid1056/PQSMsg.h | 853 +++++++++++++++++++++++++++++++++++++- LFtid1056/client2.cpp | 212 ++++++++-- LFtid1056/client2.h | 86 +++- LFtid1056/dealMsg.cpp | 270 +++++++++++- LFtid1056/main_thread.cpp | 6 +- 6 files changed, 1537 insertions(+), 44 deletions(-) diff --git a/LFtid1056/PQSMsg.cpp b/LFtid1056/PQSMsg.cpp index 225d669..35a87a5 100644 --- a/LFtid1056/PQSMsg.cpp +++ b/LFtid1056/PQSMsg.cpp @@ -76,6 +76,139 @@ unsigned char GetCrcSum(const std::vector& Check, int nOffset, in 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) { // 参数检查 @@ -237,3 +370,24 @@ std::vector generate_realstat_message(unsigned char nCpuNo, 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)); +} \ No newline at end of file diff --git a/LFtid1056/PQSMsg.h b/LFtid1056/PQSMsg.h index 6419cfc..889a4ca 100644 --- a/LFtid1056/PQSMsg.h +++ b/LFtid1056/PQSMsg.h @@ -9,13 +9,13 @@ #include #include // 字节序转换 #include +#include using namespace std; float IntToFloat(int num); float ShorToFloat100(short num); float ShorToFloat1000(short num); float ShorToFloat10000(short num); - // 发送报文功能码枚举 enum class MsgRequestType : unsigned char { //询问统计数据时间 @@ -23,7 +23,9 @@ enum class MsgRequestType : unsigned char { //询问统计数据 Request_Stat = 0x8a, //询问实时数据 - Request_New_3S = 0x04 + Request_New_3S = 0x04, + //下载装置文件 + Request_File_Download = 0x07 }; // 接收报文功能码枚举 enum class MsgResponseType : unsigned char { @@ -32,7 +34,13 @@ enum class MsgResponseType : unsigned char { //询问统计数据 Response_Stat = 0x26, //询问实时数据 - Response_New_3S = 0x84 + Response_New_3S = 0x84, + //主动上送的暂态事件 + Response_Event = 0x16, + //主动上送的波形文件信息事件 + Response_ActiveSOEInfo = 0x17, + //下载装置文件 + Response_File_Download = 0x87 }; //基础消息结构 class MessageParser { @@ -688,6 +696,472 @@ public: return count; } + + //角型接线转换 + std::string ConvertToBase64_Delta() const { + std::vector float_buffer; + + // 0-8位从Rms取0-8 + for (int i = 0; i < 9; ++i) { + float_buffer.push_back(Rms[i]); + } + + // 9-11位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 12-14位从UU_Deviation和UL_Deviation各自取前三个,取不为0的值 + for (int i = 0; i < 3; ++i) { + float val = (UU_Deviation[i] != 0.0f) ? UU_Deviation[i] : UL_Deviation[i]; + float_buffer.push_back(val); + } + + // 15-16位从F_Deviation中取0-1 + for (int i = 0; i < 2; ++i) { + float_buffer.push_back(F_Deviation[i]); + } + + // 再后8位从UI_Seq取0-7 + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 4; ++j) { + if (i * 4 + j < 8) { // 只取前8个 + float_buffer.push_back(UI_Seq[i][j]); + } + } + } + + // 再后49*3位置位3.1415表示空置 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后49位从FuHarm的3中取1-49位 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[3][i]); + } + + // 再后49位从FuHarm的4中取1-49位 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[4][i]); + } + + // 再后49位从FuHarm的5中取1-49位 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[5][i]); + } + + // 再后49*3位从FuHarm的0-2中取1-49位 + for (int j = 0; j < 3; ++j) { + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[j][i]); + } + } + + // 再后49*3位置位3.1415表示空置 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后49*3位依次从FuHarmPhase的3-5中取1-49位 + for (int j = 3; j < 6; ++j) { + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarmPhase[j][i]); + } + } + + // 再后49*3位依次从FuHarmPhase的0-2中取1-49位 + for (int j = 0; j < 3; ++j) { + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarmPhase[j][i]); + } + } + + // 再后50*3位置位3.1415表示空置 + for (int i = 0; i < 50 * 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后50*3位依次从InHarm的3-5中取0-49位中的val指标 + for (int j = 3; j < 6; ++j) { + for (int i = 0; i < HARMNUM; ++i) { + float_buffer.push_back(InHarm[j][i].Val); + } + } + + // 再后50*3位依次从InHarm的0-2中取0-49位中的val指标 + for (int j = 0; j < 3; ++j) { + for (int i = 0; i < HARMNUM; ++i) { + float_buffer.push_back(InHarm[j][i].Val); + } + } + + // 再后12位依次从Total_Power的0-3中取0-2位 + for (int j = 0; j < 4; ++j) { + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(Total_Power[j][i]); + } + } + + // 再后49位从Harm_Power中取0的1-49中的P值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[0][i].P); + } + + // 再后49位从Harm_Power中取0的1-49中的Q值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[0][i].Q); + } + + // 再后49位从Harm_Power中取0的1-49中的S值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[0][i].S); + } + + // 再后49位从Harm_Power中取1的1-49中的P值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[1][i].P); + } + + // 再后49位从Harm_Power中取1的1-49中的Q值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[1][i].Q); + } + + // 再后49位从Harm_Power中取1的1-49中的S值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[1][i].S); + } + + // 再后49位从Harm_Power中取2的1-49中的P值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[2][i].P); + } + + // 再后49位从Harm_Power中取2的1-49中的Q值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[2][i].Q); + } + + // 再后49位从Harm_Power中取2的1-49中的S值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[2][i].S); + } + + // 再后49位从Harm_Power中取3的1-49中的P值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[3][i].P); + } + + // 再后49位从Harm_Power中取3的1-49中的Q值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[3][i].Q); + } + + // 再后49位从Harm_Power中取3的1-49中的S值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[3][i].S); + } + + // 再后49*3位置位3.1415表示空置 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后49*3位从Harm_Contain中的3-5中取1-49位 + for (int j = 3; j < 6; ++j) { + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Contain[j][i]); + } + } + + // 再后49*3位从Harm_Contain中的0-2中取1-49位 + for (int j = 0; j < 3; ++j) { + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Contain[j][i]); + } + } + + // 再后3位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后3位从Harm_Aberrance中的3-5中取值 + for (int i = 3; i < 6; ++i) { + float_buffer.push_back(Harm_Aberrance[i]); + } + + // 再后3位从Harm_Aberrance中的0-2中取值 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(Harm_Aberrance[i]); + } + + // 再后4位从Cos_PF中取0-3 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(Cos_PF[i]); + } + + // 再后4位从Cos_DF中取0-3 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(Cos_DF[i]); + } + + // 再后3位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后3位从U_Fluctuation中取0-2 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(U_Fluctuation[i]); + } + + // 再后3位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后3位从U_Flicker中取0-2 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(U_Flicker[i]); + } + + // 再后3位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后3位从UL_Flicker中取0-2 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(UL_Flicker[i]); + } + + // 转换为Base64 + const size_t byte_size = float_buffer.size() * sizeof(float); + const unsigned char* byte_data = reinterpret_cast(float_buffer.data()); + return base64_encode(byte_data, byte_size); + } + + //星型接线转换 + std::string ConvertToBase64_Star() const { + std::vector float_buffer; + + // 0-8位从Rms取0-8 + for (int i = 0; i < 9; ++i) { + float_buffer.push_back(Rms[i]); + } + + // 9-11位从UU_Deviation和UL_Deviation各自取前三个,取不为0的值 + for (int i = 0; i < 3; ++i) { + float val = (UU_Deviation[i] != 0.0f) ? UU_Deviation[i] : UL_Deviation[i]; + float_buffer.push_back(val); + } + + // 12-14位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 15-16位从F_Deviation中取0-1 + for (int i = 0; i < 2; ++i) { + float_buffer.push_back(F_Deviation[i]); + } + + // 再后8位从UI_Seq取0-7 + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 4; ++j) { + if (i * 4 + j < 8) { // 只取前8个 + float_buffer.push_back(UI_Seq[i][j]); + } + } + } + + // 再后49位从FuHarm的0中取1-49位 (注意数组从0开始) + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[0][i]); + } + // 再后49位从FuHarm的1中取1-49位 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[1][i]); + } + // 再后49位从FuHarm的2中取1-49位 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[2][i]); + } + // 再后49位从FuHarm的3中取1-49位 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[3][i]); + } + // 再后49位从FuHarm的4中取1-49位 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[4][i]); + } + // 再后49位从FuHarm的5中取1-49位 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarm[5][i]); + } + // 再后49*3位置位3.1415表示空置 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后49*3位依次从FuHarmPhase的0-2中取1-49位 + for (int j = 0; j < 3; ++j) { + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarmPhase[j][i]); + } + } + // 再后49*3位依次从FuHarmPhase的3-5中取1-49位 + for (int j = 3; j < 6; ++j) { + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(FuHarmPhase[j][i]); + } + } + // 再后49*3位置位3.1415表示空置 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后50*6位依次从InHarm的0-5中取0-49位中的val指标 + for (int j = 0; j < 6; ++j) { + for (int i = 0; i < HARMNUM; ++i) { + float_buffer.push_back(InHarm[j][i].Val); + } + } + // 再后50*3位置位3.1415表示空置 + for (int i = 0; i < 50 * 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后12位依次从Total_Power的0-3中取0-2位 + for (int j = 0; j < 4; ++j) { + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(Total_Power[j][i]); + } + } + + // 再后49位从Harm_Power中取0的1-49中的P值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[0][i].P); + } + // 再后49位从Harm_Power中取0的1-49中的Q值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[0][i].Q); + } + // 再后49位从Harm_Power中取0的1-49中的S值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[0][i].S); + } + // 再后49位从Harm_Power中取1的1-49中的P值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[1][i].P); + } + // 再后49位从Harm_Power中取1的1-49中的Q值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[1][i].Q); + } + // 再后49位从Harm_Power中取1的1-49中的S值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[1][i].S); + } + // 再后49位从Harm_Power中取2的1-49中的P值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[2][i].P); + } + // 再后49位从Harm_Power中取2的1-49中的Q值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[2][i].Q); + } + // 再后49位从Harm_Power中取2的1-49中的S值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[2][i].S); + } + // 再后49位从Harm_Power中取3的1-49中的P值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[3][i].P); + } + // 再后49位从Harm_Power中取3的1-49中的Q值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[3][i].Q); + } + // 再后49位从Harm_Power中取3的1-49中的S值 + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Power[3][i].S); + } + + // 再后49*6位从Harm_Contain中的0-5中取1-49位 + for (int j = 0; j < 6; ++j) { + for (int i = 1; i < HARMNUM; ++i) { + float_buffer.push_back(Harm_Contain[j][i]); + } + } + // 再后49*3位置位3.1415表示空置 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后6位从Harm_Aberrance中的0-5中取值 + for (int i = 0; i < 6; ++i) { + float_buffer.push_back(Harm_Aberrance[i]); + } + // 再后3位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后4位从Cos_PF中取0-3 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(Cos_PF[i]); + } + // 再后4位从Cos_DF中取0-3 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(Cos_DF[i]); + } + + // 再后3位从U_Fluctuation中取0-2 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(U_Fluctuation[i]); + } + // 再后3位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后3位从U_Flicker中取0-2 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(U_Flicker[i]); + } + // 再后3位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 再后3位从UL_Flicker中取0-2 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(UL_Flicker[i]); + } + // 再后3位置位3.1415表示空置 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 转换为Base64 + const size_t byte_size = float_buffer.size() * sizeof(float); + const unsigned char* byte_data = reinterpret_cast(float_buffer.data()); + return base64_encode(byte_data, byte_size); + } + + //传入接线方式选择转换方式 + std::string ConvertToBase64(int type) const { + //1为角型接线,不符合则默认走星型转换逻辑 + if (type == 1) { + return ConvertToBase64_Delta(); + } + else { + return ConvertToBase64_Star(); + } + } private: // 序列化浮点数据到缓冲区 void SerializeFloats(std::vector& buffer) const { @@ -1203,8 +1677,377 @@ public: return base64_encode(byte_data, byte_size); } + + std::string floatVectorToBase64(const std::vector& float_buffer) const { + const size_t byte_size = float_buffer.size() * sizeof(float); + const unsigned char* byte_data = + reinterpret_cast(float_buffer.data()); + + return base64_encode(byte_data, byte_size); + } + + // 星型接线转换函数 + std::string ConvertToBase64_Star() const { + std::vector float_buffer; + + // 0-8: RMS值 + for (int i = 0; i < 9; ++i) { + float_buffer.push_back(Rms[i]); + } + + // 9-11: 电压偏差(取不为0的值) + for (int i = 0; i < 3; ++i) { + float val = (UU_Deviation[i] != 0.0f) ? UU_Deviation[i] : UL_Deviation[i]; + float_buffer.push_back(val); + } + + // 12-14: 空置(线电压位置) + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 15-20: THD总畸变率(0-5) + for (int i = 0; i < 6; ++i) { + float_buffer.push_back(THD[i]); + } + + // 21-23: 空置(线电压THD) + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 24-25: 频率及偏差 + for (int i = 0; i < 2; ++i) { + float_buffer.push_back(FREQ[i]); + } + + // 26-33: 电压电流序分量(前8个元素) + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 4; ++j) { // 取每行的前4个元素 + if (i == 0 || j < 3) { // 确保只取8个 + float_buffer.push_back(UI_Seq[i][j]); + } + } + } + + // 34-45: 总功率 + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 3; ++j) { + float_buffer.push_back(TOTAL_POWER[i][j]); + } + } + + // 46-49: 视在功率因数 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(COS_PF[i]); + } + + // 50-53: 位移功率因数 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(COS_DF[i]); + } + + // 54-200: 电压谐波含有率(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMV[i][j]); + } + } + + // 201-347: 空置(线电压谐波) + for (int i = 0; i < 3 * 49; ++i) { + float_buffer.push_back(3.1415f); + } + + // 348-494: 电流谐波幅值(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMI[i][j]); + } + } + + // 495-641: 电压谐波相位(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMVP[i][j]); + } + } + + // 642-788: 空置(线电压谐波相位) + for (int i = 0; i < 3 * 49; ++i) { + float_buffer.push_back(3.1415f); + } + + // 789-935: 电流谐波相位(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMIP[i][j]); + } + } + + // 936-1085: 电压间谐波幅值(0-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < HARMNUM; ++j) { + float_buffer.push_back(INHARMV[i][j]); + } + } + + // 1086-1235: 空置(线电压间谐波) + for (int i = 0; i < 3 * 50; ++i) { + float_buffer.push_back(3.1415f); + } + + // 转换为Base64 + return floatVectorToBase64(float_buffer); + } + + // 角型接线转换函数 + std::string ConvertToBase64_Delta() const { + std::vector float_buffer; + + // 0-8: RMS值 + for (int i = 0; i < 9; ++i) { + float_buffer.push_back(Rms[i]); + } + + // 9-11: 空置(相电压位置) + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 12-14: 电压偏差(取不为0的值) + for (int i = 0; i < 3; ++i) { + float val = (UU_Deviation[i] != 0.0f) ? UU_Deviation[i] : UL_Deviation[i]; + float_buffer.push_back(val); + } + + // 15-17: 空置(相电压THD) + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.1415f); + } + + // 18-20: THD线电压畸变率(3-5) + for (int i = 3; i < 6; ++i) { + float_buffer.push_back(THD[i]); + } + + // 21-23: THD相电压畸变率(0-2) + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(THD[i]); + } + + // 24-25: 频率及偏差 + for (int i = 0; i < 2; ++i) { + float_buffer.push_back(FREQ[i]); + } + + // 26-33: 电压电流序分量(前8个元素) + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 4; ++j) { + if (i == 0 || j < 3) { + float_buffer.push_back(UI_Seq[i][j]); + } + } + } + + // 34-45: 总功率 + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 3; ++j) { + float_buffer.push_back(TOTAL_POWER[i][j]); + } + } + + // 46-49: 视在功率因数 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(COS_PF[i]); + } + + // 50-53: 位移功率因数 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(COS_DF[i]); + } + + // 54-200: 空置(相电压谐波) + for (int i = 0; i < 3 * 49; ++i) { + float_buffer.push_back(3.1415f); + } + + // 201-347: 电压谐波含有率(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMV[i][j]); + } + } + + // 348-494: 电流谐波幅值(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMI[i][j]); + } + } + + // 495-641: 空置(相电压谐波相位) + for (int i = 0; i < 3 * 49; ++i) { + float_buffer.push_back(3.1415f); + } + + // 642-788: 电压谐波相位(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMVP[i][j]); + } + } + + // 789-935: 电流谐波相位(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMIP[i][j]); + } + } + + // 936-1085: 空置(线电压间谐波) + for (int i = 0; i < 3 * 50; ++i) { + float_buffer.push_back(3.1415f); + } + + // 1086-1235: 电压间谐波幅值(0-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < HARMNUM; ++j) { + float_buffer.push_back(INHARMV[i][j]); + } + } + + // 转换为Base64 + return floatVectorToBase64(float_buffer); + } + + // 根据接线方式选择转换方法 + std::string ConvertToBase64(int wiringType) const { + // 1为角型接线,其他为星型接线 + if (wiringType == 1) { + return ConvertToBase64_Delta(); + } + else { + return ConvertToBase64_Star(); + } + } }; #pragma pack(pop) + +//暂态相关结构------------------------------ +#pragma pack(push, 1) + +// 时间结构体 +struct TagMsTime { + uint16_t Year; + uint16_t Month; + uint16_t Day; + uint16_t Hour; + uint16_t Min; + uint16_t Sec; + uint16_t Ms; + + void convertByteOrder() { + Year = ntohs(Year); + Month = ntohs(Month); + Day = ntohs(Day); + Hour = ntohs(Hour); + Min = ntohs(Min); + Sec = ntohs(Sec); + Ms = ntohs(Ms); + } +}; + +// 告警事件头结构 +struct NewHeadTaglogbuffer { + uint16_t name; // 监测点序号 + TagMsTime Devtime; // 绝对时间 + uint16_t LogType; // 日志类型 + uint16_t LogCode; // 日志代码 + uint16_t LogLb; // 日志录波 + uint16_t LogBackup; // 日志补零位 + uint32_t LogParaNum; // 日志参数项数 + + void convertByteOrder() { + name = ntohs(name); + Devtime.convertByteOrder(); + LogType = ntohs(LogType); + LogCode = ntohs(LogCode); + LogLb = ntohs(LogLb); + LogBackup = ntohs(LogBackup); + LogParaNum = ntohl(LogParaNum); + } +}; + +// 告警事件身体结构 +struct NewBodyTaglogbuffer { + uint32_t ParaCode; // 参数编码 + uint32_t ParaValue; // 参数值 + + void convertByteOrder() { + ParaCode = ntohl(ParaCode); + ParaValue = ntohl(ParaValue); + } +}; + +// 告警事件完整结构 +class NewTaglogbuffer { +public: + NewHeadTaglogbuffer head; + std::vector bodyList; + + // 从字节流解析数据 + void parseFromData(const uint8_t* data, size_t data_size) { + // 解析头部 + if (data_size < sizeof(NewHeadTaglogbuffer)) { + throw std::runtime_error("Insufficient data for header"); + } + + memcpy(&head, data, sizeof(NewHeadTaglogbuffer)); + head.convertByteOrder(); + + // 解析身体部分 + const size_t body_start = sizeof(NewHeadTaglogbuffer); + const size_t body_size = head.LogParaNum * sizeof(NewBodyTaglogbuffer); + + if (data_size < body_start + body_size) { + throw std::runtime_error("Insufficient data for body"); + } + + bodyList.resize(head.LogParaNum); + const uint8_t* body_data = data + body_start; + + for (uint32_t i = 0; i < head.LogParaNum; ++i) { + memcpy(&bodyList[i], body_data, sizeof(NewBodyTaglogbuffer)); + bodyList[i].convertByteOrder(); + body_data += sizeof(NewBodyTaglogbuffer); + } + } + + // 创建对象的方法(类似C#的工厂方法) + static NewTaglogbuffer createFromData(const uint8_t* data, size_t data_size) { + NewTaglogbuffer result; + result.parseFromData(data, data_size); + return result; + } +}; + +#pragma pack(pop) + +// 定义QVVRRecord结构体 +struct QVVRRecord { + uint64_t triggerTimeMs; // 毫秒时间戳(UTC,从1970-01-01 00:00:00开始) + int nType = 0; // 事件类型:0-未知 1-暂降 2-暂升 3-中断 4-瞬态 + float fPersisstime = 0.0f; // 持续时间(秒) + float fMagntitude = 0.0f; // 特征幅值(标幺值) + float phase = 0.0f; // 相别(瞬态使用)0-A 1-B 2-C 3-AB 4-BC 5-CA ?-ABC + float transientValue = 0.0f;// 瞬变幅度(瞬态使用) +}; + +// 解析日志生成QVVRRecord +QVVRRecord DynamicLog_GetQVVRRecordFromLogBuffer(const std::string& strScale, uint32_t nPTType, float fPT, const NewTaglogbuffer& log); +//暂态相关结构------------------------------- + // 生成带协议头的二进制报文 std::vector generate_binary_message( uint16_t msg_type, @@ -1217,4 +2060,6 @@ std::vector generate_statequerytime_message(); //生成询问统计数据报文 std::vector generate_statequerystat_message(tagTime time, uint16_t nDeviceNo, uint16_t nDataType); //生成询问实时数据报文 -std::vector generate_realstat_message(unsigned char nCpuNo, unsigned char StaTtype, unsigned char flag); \ No newline at end of file +std::vector generate_realstat_message(unsigned char nCpuNo, unsigned char StaTtype, unsigned char flag); +//生成文件下载请求报文 当前帧序号+文件名 +std::vector generate_downloadfile_message(int frameIndex, const std::string& fileName); \ No newline at end of file diff --git a/LFtid1056/client2.cpp b/LFtid1056/client2.cpp index d4211ff..60ca66e 100644 --- a/LFtid1056/client2.cpp +++ b/LFtid1056/client2.cpp @@ -248,7 +248,7 @@ void ClientContext::process_next_action() { // 鏂板鏂规硶锛氬彂閫佸綋鍓嶇姸鎬佸搴旂殑鎶ユ枃 void ClientContext::send_current_packet() { if (!current_packet_.empty()) { - send_binary_data(this, current_packet_.data(), current_packet_.size()); + safe_send_binary_data(this, current_packet_); } } @@ -417,6 +417,37 @@ void send_binary_data(ClientContext* ctx, const unsigned char* data, size_t data } } +// 鏂板鍑芥暟锛氬湪浜嬩欢寰幆绾跨▼涓畨鍏ㄥ彂閫佹暟鎹 +void safe_send_binary_data(ClientContext* ctx, std::vector data) { + uv_work_t* req = new uv_work_t; + req->data = new std::pair>(ctx, std::move(data)); + + uv_queue_work(ctx->loop, req, [](uv_work_t* req) { + // 鍦ㄥ伐浣滅嚎绋嬩腑涓嶆墽琛屽疄闄呭伐浣 + }, [](uv_work_t* req, int status) { + // 鍦ㄤ簨浠跺惊鐜嚎绋嬩腑鎵ц瀹為檯鍙戦 + auto* pair = static_cast>*>(req->data); + ClientContext* ctx = pair->first; + const auto& data = pair->second; + + if (ctx->state == ConnectionState::CONNECTED) { + // 瀹為檯鍙戦侀昏緫锛堝師 send_binary_data 鐨勬牳蹇冮儴鍒嗭級 + uv_buf_t buf = uv_buf_init(const_cast(reinterpret_cast(data.data())), data.size()); + uv_write_t* write_req = new uv_write_t; + write_req->data = new std::vector(data); // 澶嶅埗鏁版嵁 + + int ret = uv_write(write_req, (uv_stream_t*)&ctx->client, &buf, 1, on_write); + if (ret < 0) { + // 閿欒澶勭悊 + delete static_cast*>(write_req->data); + delete write_req; + } + } + + delete pair; + delete req; + }); +} /* 杩炴帴鍏抽棴鍥炶皟 */ void on_close(uv_handle_t* handle) { ClientContext* ctx = static_cast(handle->data); @@ -503,7 +534,7 @@ void on_connect(uv_connect_t* req, int status) { //瀹㈡埛绔繛鎺ュ畬姣曞悗锛屽彂閫佽缃櫥闄嗘秷鎭 std::cout << "connected: " << ctx->device_info.mac << " send login msg!" << std::endl; auto binary_data = generate_frontlogin_message(ctx->device_info.mac); - send_binary_data(ctx, binary_data.data(), binary_data.size()); + safe_send_binary_data(ctx, binary_data); uv_read_start((uv_stream_t*)&ctx->client, alloc_buffer, on_read); ctx->start_timer(); @@ -623,30 +654,6 @@ void ClientManager::remove_device(const std::string& device_id) { std::cout << "[Device " << device_id << "] Removed successfully\n"; } -bool ClientManager::send_to_device(const std::string& identifier, - const unsigned char* data, - size_t size) { - std::lock_guard lock(mutex_); - - for (auto& pair : clients_) { - auto& ctx = pair.second; - // 鍖归厤瑁呯疆ID鎴朚AC鍦板潃 - if (ctx->device_info.device_id == identifier || - ctx->device_info.mac == identifier) { - - if (ctx->state == ConnectionState::CONNECTED) { - send_binary_data(ctx.get(), data, size); - return true; - } - std::cerr << "[Device " << identifier << "] Not connected\n"; - return false; - } - } - - std::cerr << "[Device " << identifier << "] Not found\n"; - return false; -} - void ClientManager::stop_all() { std::lock_guard lock(mutex_); for (auto& pair : clients_) { @@ -1011,4 +1018,157 @@ bool ClientManager::set_real_state_count(const std::string& identifier, int coun std::cerr << "[set_real_state_count] Device not found: " << identifier << std::endl; return false; +} + +bool ClientManager::get_point_scale_and_pttype(const std::string& identifier, + ushort nCpuNo, + std::string& out_scale, + int& out_pttype) { + std::lock_guard lock(mutex_); + + // 閬嶅巻鎵鏈夊鎴风涓婁笅鏂 + for (auto& pair : clients_) { + auto& ctx = pair.second; + + // 妫鏌ユ爣璇嗙鏄惁鍖归厤璁惧ID鎴朚AC鍦板潃 + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) { + + // 鍦ㄨ缃殑娴嬬偣鍒楄〃涓煡鎵惧尮閰嶇殑娴嬬偣 + for (const auto& point : ctx->device_info.points) { + if (point.nCpuNo == nCpuNo) { + out_scale = point.strScale; + out_pttype = point.nPTType; + return true; + } + } + + // 娴嬬偣鏈壘鍒 + std::cerr << "Point with nCpuNo " << nCpuNo + << " not found for device: " << identifier << std::endl; + return false; + } + } + + // 璁惧鏈壘鍒 + std::cerr << "Device not found: " << identifier << std::endl; + return false; +} + +//淇敼寰呭彂閫佹姤鏂囩殑甯у簭鍙凤紙浠呭湪鏆傛佹枃浠朵腑浣跨敤锛 +bool ClientManager::update_current_packet_frame(const std::string& identifier, int next_frame) { + std::lock_guard lock(mutex_); + + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || ctx->device_info.mac == identifier) { + std::lock_guard state_lock(ctx->state_mutex_); + + // 妫鏌ユ姤鏂囬暱搴︽槸鍚﹁冻澶 + if (ctx->current_packet_.size() < 16) { + std::cerr << "Packet too short to update frame number" << std::endl; + return false; + } + + // 灏忕搴忓啓鍏ユ柊甯у簭鍙 (浣嶇疆12-15瀛楄妭) + ctx->current_packet_[12] = (next_frame >> 0) & 0xFF; + ctx->current_packet_[13] = (next_frame >> 8) & 0xFF; + ctx->current_packet_[14] = (next_frame >> 16) & 0xFF; + ctx->current_packet_[15] = (next_frame >> 24) & 0xFF; + + return true; + } + } + return false; +} + +bool ClientManager::parse_download_packet(const std::string& identifier, DownloadInfo& out_info) { + std::lock_guard lock(mutex_); + + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) { + + // 鑾峰彇褰撳墠鐘舵佹姤鏂 + std::vector current_packet; + { + std::lock_guard state_lock(ctx->state_mutex_); + current_packet = ctx->current_packet_; + } + + // 瑙f瀽甯у簭鍙 (12-15瀛楄妭灏忕搴) + if (current_packet.size() >= 16) { + out_info.current_frame = + (static_cast(current_packet[12])) | + (static_cast(current_packet[13]) << 8) | + (static_cast(current_packet[14]) << 16) | + (static_cast(current_packet[15]) << 24); + + // 瑙f瀽鏂囦欢鍚 (浠庡亸绉婚噺16寮濮) + if (current_packet.size() > 16) { + const char* filename_start = reinterpret_cast(current_packet.data()) + 16; + size_t filename_len = 128; + out_info.filename.assign(filename_start, filename_len); + return true; + } + } + } + } + return false; +} + +bool ClientManager::add_file_packet_to_device(const std::string& identifier, + int frame_index, + const unsigned char* data, + size_t size) { + std::lock_guard lock(mutex_); + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) { + ctx->add_file_packet(frame_index, data, size); + return true; + } + } + return false; +} + +std::vector> +ClientManager::get_and_clear_file_packets(const std::string& identifier) { + std::lock_guard lock(mutex_); + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) { + return ctx->get_and_clear_file_packets(); + } + } + return {}; +} + +bool ClientManager::update_current_filename(const std::string& identifier, + const std::string& filename) { + std::lock_guard lock(mutex_); + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) { + ctx->set_current_filename(filename); + return true; + } + } + return false; +} + +std::string ClientManager::get_current_filename(const std::string& identifier) { + std::lock_guard lock(mutex_); + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) { + return ctx->get_current_filename(); + } + } + return ""; } \ No newline at end of file diff --git a/LFtid1056/client2.h b/LFtid1056/client2.h index acc9bb2..6fec92c 100644 --- a/LFtid1056/client2.h +++ b/LFtid1056/client2.h @@ -20,6 +20,8 @@ struct PointInfo { double PT2; // 电压变比2 double CT1; // 电流变比1 double CT2; // 电流变比2 + std::string strScale; // 电压等级 + int nPTType; // 接线方式 0-星型 1-角型 }; // 装置信息结构 @@ -44,6 +46,7 @@ enum class DeviceState { READING_STATS, // 读取统计数据 READING_STATS_TIME, // 读取统计时间 READING_REALSTAT, // 读取实时数据 + READING_EVENTFILE, // 暂态波形文件下载 // 可根据需要添加更多状态 CUSTOM_ACTION // 自定义动作 }; @@ -161,6 +164,60 @@ public: realtime_packets_cache_.clear(); } + //暂态文件下载相关 + struct FileDownloadPacket { + int frame_index; + std::vector data; + }; + + std::vector file_download_cache_; // 文件分片缓存 + std::string current_filename_; // 当前下载的文件名 + std::mutex file_cache_mutex_; // 缓存互斥锁 + + // 添加文件分片到缓存 + void add_file_packet(int frame_index, const unsigned char* data, size_t size) { + std::lock_guard lock(file_cache_mutex_); + file_download_cache_.push_back({ frame_index, std::vector(data, data + size) }); + } + + // 获取并清空缓存中的所有分片(按帧序号排序) + std::vector> get_and_clear_file_packets() { + std::lock_guard lock(file_cache_mutex_); + + // 按帧序号排序 + std::sort(file_download_cache_.begin(), file_download_cache_.end(), + [](const FileDownloadPacket& a, const FileDownloadPacket& b) { + return a.frame_index < b.frame_index; + }); + + // 提取数据 + std::vector> packets; + for (const auto& pkt : file_download_cache_) { + packets.push_back(pkt.data); + } + + // 清空缓存 + file_download_cache_.clear(); + return packets; + } + + // 清空文件缓存 + void clear_file_cache() { + std::lock_guard lock(file_cache_mutex_); + file_download_cache_.clear(); + } + + // 设置当前下载的文件名 + void set_current_filename(const std::string& filename) { + std::lock_guard lock(file_cache_mutex_); + current_filename_ = filename; + } + + // 获取当前下载的文件名 + std::string get_current_filename() { + std::lock_guard lock(file_cache_mutex_); + return current_filename_; + } private: int index_; @@ -185,7 +242,6 @@ public: void add_device(const DeviceInfo& device);//添加一个装置连接 void remove_device(const std::string& device_id);//删除一个装置连接 - bool send_to_device(const std::string& identifier, const unsigned char* data, size_t size);//选择指定的装置发送消息至服务端 void restart_device(const std::string& device_id);//关闭指定装置连接,等待重连唤起 void stop_all();//停止所有客户端连接 bool set_cloud_status(const std::string& identifier, int status);//修改云前置登录状态 @@ -279,6 +335,33 @@ public: } return {}; } + + // 获取指定测点的电压等级和接线方式 + bool get_point_scale_and_pttype(const std::string& identifier, + ushort nCpuNo, + std::string& out_scale, + int& out_pttype); + + //修改暂态相关文件报文的帧序号 + bool update_current_packet_frame(const std::string& identifier, int next_frame); + + //获取暂态文件下载报文中的信息 + struct DownloadInfo { + std::string filename; + int current_frame; + }; + bool parse_download_packet(const std::string& identifier, DownloadInfo& out_info); + + bool add_file_packet_to_device(const std::string& identifier, + int frame_index, + const unsigned char* data, + size_t size); + + std::vector> get_and_clear_file_packets(const std::string& identifier); + + bool update_current_filename(const std::string& identifier, const std::string& filename); + + std::string get_current_filename(const std::string& identifier); private: ClientManager() : loop_(nullptr) {} std::unordered_map> clients_; @@ -289,6 +372,7 @@ private: // 函数声明 void start_client_connect(const std::vector& devices); void send_binary_data(ClientContext* ctx, const unsigned char* data, size_t data_size); +void safe_send_binary_data(ClientContext* ctx, std::vector data); void on_timer(uv_timer_t* handle); void try_reconnect(uv_timer_t* timer); void on_connect(uv_connect_t* req, int status); diff --git a/LFtid1056/dealMsg.cpp b/LFtid1056/dealMsg.cpp index 3fdb929..f0dca5a 100644 --- a/LFtid1056/dealMsg.cpp +++ b/LFtid1056/dealMsg.cpp @@ -7,7 +7,8 @@ #include #include #include - +#include +#include // 用于mkdir #include #include "cloudfront/code/interface.h" //lnk20250708 @@ -32,12 +33,23 @@ time_t ConvertToTimestamp(const tagPqData_Float& data) { return mktime(&t); } +//文件分割取字段 +std::string extract_filename(const std::string& path) { + // 查找最后一个'/'的位置 + size_t last_slash = path.find_last_of('/'); + + // 如果找到'/',则返回'/'之后的部分 + if (last_slash != std::string::npos) { + return path.substr(last_slash + 1); + } + + // 如果没有'/',直接返回原字符串 + return path; +} void process_received_message(string mac, string id,const char* data, size_t length) { // 实际的消息处理逻辑 - // 这里可以添加您的业务处理代码 std::cout << "Active connections: " << mac << " id:" << id << " size:" << length << std::endl; // 示例:解析消息并处理 - // 注意:根据您的协议实现具体的解析逻辑 //数据处理逻辑 if (length > 0) { @@ -72,7 +84,142 @@ void process_received_message(string mac, string id,const char* data, size_t len //登录报文处理完毕,当前报文处理逻辑结束并返回 return; } + //装置主动上送报文 暂态事件报文/暂态波形文件报文 + if (udata[8] == static_cast(MsgResponseType::Response_Event)) { + //处理主动上送的暂态事件报文 + NewTaglogbuffer event = NewTaglogbuffer::createFromData(parser.RecvData.data(), parser.RecvData.size()); + // 获取测点参数 + std::string strScale;//电压等级 + int nPTType;//接线方式 + float fPT = 1.0f; + float fCT = 1.0f; + if (ClientManager::instance().get_point_scale_and_pttype( + id, // 或使用id + event.head.name, // 从报文中解析出的测点序号 + strScale, + nPTType) && ClientManager::instance().get_pt_ct_ratio(id, event.head.name, fPT, fCT)) + { + // 使用获取的参数解析事件记录 + QVVRRecord record = DynamicLog_GetQVVRRecordFromLogBuffer( + strScale, nPTType, fPT, event); + + // 使用记录数据(示例:打印到控制台) + std::cout << "事件类型: " << record.nType + << ", 持续时间: " << record.fPersisstime << "s" + << ", 特征幅值: " << record.fMagntitude << " pu" + << ", 时间戳: " << record.triggerTimeMs << "ms" << std::endl; + + } + else { + // 处理获取失败的情况 + std::cerr << "Failed to get point parameters for: " << mac << std::endl; + } + //处理完毕主动上送报文后直接退出,不要干扰装置正常应答 + return; + } + else if (udata[8] == static_cast(MsgResponseType::Response_ActiveSOEInfo)) { + //处理主动上送的波形文件信息报文 + unsigned char file_type = udata[12];//录波文件类型数 cfg dat hdr 1-3 + unsigned char line_id = udata[13];//录波测点 1-6 + const uint8_t* data_ptr = parser.RecvData.data() + 2;//数据体去除前两位 + size_t data_size = parser.RecvData.size() - 2; + // 直接构造字符串(避免额外拷贝) + std::string tempfilename( + reinterpret_cast(data_ptr), + data_size + ); + + // ========== 新增文件路径处理逻辑 ========== + // 1. 分割原始文件名和后缀 + size_t dotPos = tempfilename.find_last_of('.'); + std::string baseName, originalExt; + if (dotPos != std::string::npos) { + baseName = tempfilename.substr(0, dotPos); + originalExt = tempfilename.substr(dotPos); + } + else { + baseName = tempfilename; + originalExt = ""; + } + + // 2. 确定大小写风格 + bool isUppercase = false; + if (!originalExt.empty()) { + isUppercase = true; + for (char c : originalExt) { + if (std::isalpha(c) && std::islower(c)) { + isUppercase = false; + break; + } + } + } + + // 3. 生成需要的后缀列表 + std::vector requiredExts; + if (file_type == 3) { // 需要三个文件 + requiredExts = { ".cfg", ".dat", ".hdr" }; + } + else { // 默认需要两个文件 + requiredExts = { ".cfg", ".dat" }; + //requiredExts = { ".dat" }; + } + + // 4. 调整后缀大小写 + if (isUppercase) { + for (auto& ext : requiredExts) { + for (char& c : ext) { + if (std::isalpha(c)) c = std::toupper(c); + } + } + } + + // 5. 构建完整路径列表 + std::vector fullFilenames; + for (const auto& ext : requiredExts) { + fullFilenames.push_back(baseName + ext); + } + + // 6. 打印结果(实际使用中可能需要替换这里的打印逻辑) + std::cout << "Generated filenames: "; + for (const auto& name : fullFilenames) { + std::cout << name << " "; + } + std::cout << std::endl; + + // ========== 新增:为每个文件生成下载请求 ========== + for (const auto& filename : fullFilenames) { + // 生成下载请求报文 (帧序号固定为1,代表开始新文件的下载) + auto downloadMsg = generate_downloadfile_message(1, filename); + + // 将下载动作添加到设备队列 + ClientManager::instance().add_action_to_device( + id, + DeviceState::READING_EVENTFILE, + downloadMsg + ); + + std::cout << "Added download request for: " << filename << std::endl; + } + + //最后报文收发处理逻辑(如果当前装置空闲则尝试执行后续动作)(如果当前装置存在其他状态则直接退出,不要干扰装置后续执行) + DeviceState currentState = DeviceState::IDLE;//获取当前装置的状态 + if (!ClientManager::instance().get_device_state(id, currentState)) { + std::cerr << "Failed to get device state for: " << id << std::endl; + return; + } + switch (currentState) { + case DeviceState::IDLE: + //当前装置空闲中,可以执行后续动作 + ClientManager::instance().post_message_processing(id); + break; + default: + //非空闲的其他状态直接退出即可,等待后续处理完毕后再尝试获取波形文件 + break; + } + //处理完毕主动上送报文后直接退出,不要干扰装置正常应答 + return; + } //常规通讯报文 { DeviceState currentState = DeviceState::IDLE;//获取当前装置的状态 @@ -170,12 +317,21 @@ void process_received_message(string mac, string id,const char* data, size_t len tagPqData_Float avg_data = all_data[2]; tagPqData_Float cp95_data = all_data[3]; - // 转换为Base64字符串 - std::string max_base64Str = max_data.ConvertToBase64(); - std::string min_base64Str = min_data.ConvertToBase64(); - std::string avg_base64Str = avg_data.ConvertToBase64(); - std::string cp95_base64Str = cp95_data.ConvertToBase64(); + std::string strScale;//电压等级 + int nPTType = 0;//接线方式 + ClientManager::instance().get_point_scale_and_pttype( + id, // 或使用id + pq_data.name, // 从报文中解析出的测点序号 + strScale, + nPTType); + // 转换为Base64字符串 + std::string max_base64Str = max_data.ConvertToBase64(nPTType); + std::string min_base64Str = min_data.ConvertToBase64(nPTType); + std::string avg_base64Str = avg_data.ConvertToBase64(nPTType); + std::string cp95_base64Str = cp95_data.ConvertToBase64(nPTType); + //std::cout << "New star base64Str0:" << max_base64Str << std::endl; + //std::cout << "New del base64Str1:" << avg_data.ConvertToBase64(1) << std::endl; //lnk20250708使用接口发送 time_t data_time = ConvertToTimestamp(avg_data); @@ -339,8 +495,16 @@ void process_received_message(string mac, string id,const char* data, size_t len } } - std::string base64 = realdata.ConvertToBase64(); - std::cout << base64 << std::endl; + std::string strScale;//电压等级 + int nPTType = 0;//接线方式 + ClientManager::instance().get_point_scale_and_pttype( + id, // 或使用id + static_cast(udata[12]), // 从报文中解析出的测点序号 + strScale, + nPTType); + + std::string base64 = realdata.ConvertToBase64(nPTType); + //std::cout << base64 << std::endl; // 处理完成后重置状态 ClientManager::instance().change_device_state(id, DeviceState::IDLE); } @@ -352,6 +516,92 @@ void process_received_message(string mac, string id,const char* data, size_t len } break; + case DeviceState::READING_EVENTFILE: + // 暂态波形文件下载 + std::cout << "READING_EVENTFILE state: Processing stats time from " << mac << std::endl; + if (udata[8] == static_cast(MsgResponseType::Response_File_Download)) { + // 提取当前帧序号(12-15字节,大端序) + int current_frame = (static_cast(udata[12]) << 24) | + (static_cast(udata[13]) << 16) | + (static_cast(udata[14]) << 8) | + static_cast(udata[15]); + + // 提取总帧数(16-19字节,大端序) + int total_frames = (static_cast(udata[16]) << 24) | + (static_cast(udata[17]) << 16) | + (static_cast(udata[18]) << 8) | + static_cast(udata[19]); + + //std::cout << "eventfile frames: " << current_frame << "/" << total_frames << std::endl; + // 将数据添加到缓存 去除数据体前14位 (逻辑稍后编写) + const uint8_t* data_ptr = parser.RecvData.data() + 14; + size_t data_size = parser.RecvData.size() - 14; + + // 如果是第一帧,记录文件名 + if (current_frame == 1) { + ClientManager::DownloadInfo info; + if (ClientManager::instance().parse_download_packet(id, info)) { + ClientManager::instance().update_current_filename(id, info.filename); + } + } + // 获取文件名 + std::string filename = ClientManager::instance().get_current_filename(id); + // 添加到缓存 + ClientManager::instance().add_file_packet_to_device(id, current_frame, data_ptr, data_size); + + //std::cout << "fileinfo: " << info.filename << "/" << info.current_frame << std::endl; + //判断是否收全,未收全则继续发送报文,收全则取出所有缓存组装文件并保存至本地,推送消息 + if (current_frame < total_frames) { + // 未收全,更新帧序号并保持状态,等待后续自动发送已修改的新报文 + int nextframe = current_frame + 1; + auto downloadMsg = generate_downloadfile_message(nextframe, filename); + ClientManager::instance().change_device_state(id, DeviceState::READING_EVENTFILE, downloadMsg); + } + else { + // 已收全,在此处处理文件 + std::cout << "mac: " << mac << " fileinfo: " << filename < file_data; + for (const auto& packet : packets) { + file_data.insert(file_data.end(), packet.begin(), packet.end()); + } + + // 保存文件 + std::string mac_dir = mac; // 使用MAC地址作为目录名 + // 创建目录(如果不存在) + if (mkdir(mac_dir.c_str(), 0777) != 0 && errno != EEXIST) { + std::cerr << "Failed to create directory: " << mac_dir << std::endl; + } + + std::string path = extract_filename(filename); + + std::string file_path = mac_dir + "/" + path; + std::ofstream out_file(file_path, std::ios::binary); + if (out_file) { + out_file.write(reinterpret_cast(file_data.data()), + file_data.size()); + std::cout << "File saved: " << file_path << std::endl; + } + else { + std::cerr << "Failed to save file: " << file_path + << ", Error: " << strerror(errno) << std::endl; + } + + //当前文件下载完毕,调整为空闲处理下一项工作(如果这里后续有新文件等待下载,一般已经存入等待队列等候处理了,调成空闲状态后直接就会开始新文件的下载工作) + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + } + else { + // 装置答非所问异常 + // 接收波形文件数据错误,调整为空闲状态,处理下一项工作。 + std::cout << "udata[8]: " << static_cast(udata[8]) << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + case DeviceState::CUSTOM_ACTION: // 自定义动作状态 std::cout << "CUSTOM_ACTION state: Processing custom response from " << mac << std::endl; diff --git a/LFtid1056/main_thread.cpp b/LFtid1056/main_thread.cpp index 3080a27..8ebaf0b 100644 --- a/LFtid1056/main_thread.cpp +++ b/LFtid1056/main_thread.cpp @@ -124,12 +124,12 @@ void* client_manager_thread(void* arg) { // 创建测点数据 std::vector points1 = { - {"P001", "Main Voltage", "D001",1 ,1, 1, 1, 1}, - {"P002", "Backup Voltage", "D001",2 ,1, 1, 1, 1} + {"P001", "Main Voltage", "D001",1 ,1, 1, 1, 1,"0.38k",0}, + {"P002", "Backup Voltage", "D001",2 ,1, 1, 1, 1,"0.38k",0} }; std::vector points2 = { - {"P101", "Generator Output", "D002",1 ,1, 1, 1, 1} + {"P101", "Generator Output", "D002",1 ,1, 1, 1, 1,"0.38k",0} }; //00-B7-8D-A8-00-D6 00-B7-8D-01-79-06 // 创建装置列表