From c388bd04fe45415a4f604f8a50a18bdbdc85a22c Mon Sep 17 00:00:00 2001 From: lnk Date: Fri, 22 May 2026 11:34:14 +0800 Subject: [PATCH] remove file after upload --- cfg_parse/cfg_parser.cpp | 31 +- json/PQSMsg.cpp | 1297 +++++++++++++++++++ json/PQSMsg.h | 2548 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 3874 insertions(+), 2 deletions(-) create mode 100644 json/PQSMsg.cpp create mode 100644 json/PQSMsg.h diff --git a/cfg_parse/cfg_parser.cpp b/cfg_parse/cfg_parser.cpp index cec7368..4bcbed8 100644 --- a/cfg_parse/cfg_parser.cpp +++ b/cfg_parse/cfg_parser.cpp @@ -5332,7 +5332,7 @@ std::string base64_encode(const std::string& in) { return out; // 返回编码后的字符串 } -void handleUploadResponse(const std::string& response, char* wavepath, int type) { +void handleUploadResponse(const std::string& response,const std::string& localPath, char* wavepath, int type) { // 解析 JSON 响应 cJSON* json_data = cJSON_Parse(response.c_str()); @@ -5390,6 +5390,33 @@ void handleUploadResponse(const std::string& response, char* wavepath, int type) std::cout << "wavepath: " << wavepath << std::endl; DIY_INFOLOG_CODE("process",0,LOG_CODE_TRANSIENT_COMM,"【NORMAL】前置上传文件成功,远端文件名:%s",wavepath); + + // ========================= + // 上传成功后删除本地文件 + // ========================= + if (remove(localPath.c_str()) == 0) + { + std::cout << "Delete local file success: " + << localPath << std::endl; + DIY_INFOLOG_CODE("process",0, + LOG_CODE_TRANSIENT_COMM, + "【NORMAL】删除本地文件成功:%s", + localPath.c_str()); + } + else + { + std::cout << "Delete local file failed: " + << localPath + << " errno=" << errno + << " err=" << strerror(errno) + << std::endl; + DIY_ERRORLOG_CODE("process",0, + LOG_CODE_TRANSIENT_COMM, + "【ERROR】删除本地文件失败:%s errno=%d err=%s", + localPath.c_str(), + errno, + strerror(errno)); + } } } else { std::cerr << "Error: Missing expected fields in JSON response." << std::endl; @@ -5513,7 +5540,7 @@ void SendFileWeb(const std::string& strUrl, const char* localpath, const char* c DIY_ERRORLOG_CODE("process",0,LOG_CODE_TRANSIENT_COMM,"【ERROR】前置上传暂态录波文件 %s 失败,请检查文件上传接口配置",localpath); } else { std::cout << "http web success, response: " << resPost0 << std::endl; - handleUploadResponse(resPost0, wavepath, type); // 处理响应 + handleUploadResponse(resPost0, localpath, wavepath, type); // 处理响应 } // 清理 diff --git a/json/PQSMsg.cpp b/json/PQSMsg.cpp new file mode 100644 index 0000000..88057f0 --- /dev/null +++ b/json/PQSMsg.cpp @@ -0,0 +1,1297 @@ +#include "../json/cjson.h" +#include "../json/mms_json_inter.h" +#include "../json/PQSMsg.h" +#include +#include +#include +#include +#include +#include +#include + +#ifndef EMPTY_FLOAT_VALUE +#define EMPTY_FLOAT_VALUE 3.14159f +#endif + +extern QMutex kafka_data_list_mutex; +extern QList kafka_data_list; + +// statType: 0=95值, 1=平均值, 2=最大值, 3=最小值 +static std::string MakeStatKey(int statType, const std::string& base) +{ + switch (statType) { + case 0: return "G_" + base; + case 1: return base; + case 2: return "MAX_" + base; + case 3: return "MIN_" + base; + default: return base; + } +} + +static cJSON* GetObj(cJSON* parent, const char* name) +{ + if (parent == NULL || name == NULL) { + return NULL; + } + return cJSON_GetObjectItem(parent, name); +} + +static float GetJsonFloat(cJSON* root, + const char* group, + const char* phase, + const std::string& key) +{ + cJSON* value = GetObj(root, "Value"); + cJSON* g = GetObj(value, group); + cJSON* p = GetObj(g, phase); + cJSON* item = GetObj(p, key.c_str()); + + if (item == NULL) { + return 0.0f; + } + + if (item && item->type == cJSON_Number) { + return static_cast(item->valuedouble); + } + + if (item && item->type == cJSON_String && item->valuestring != NULL) { + return static_cast(atof(item->valuestring)); + } + + return 0.0f; +} + +static float GetValue(cJSON* root, + int statType, + const char* group, + const char* phase, + const std::string& base) +{ + return GetJsonFloat(root, group, phase, MakeStatKey(statType, base)); +} + +static void FillDeviation(float val, float& up, float& low) +{ + if (val >= 0.0f) { + up = val; + low = 0.0f; + } else { + up = 0.0f; + low = -val; + } +} + +static long long GetJsonTimeMs(cJSON* root) +{ + cJSON* value = GetObj(root, "Value"); + cJSON* item = GetObj(value, "TIME"); + + if (item == NULL) { + return 0; + } + + if (item && item->type == cJSON_Number) { + return static_cast(item->valuedouble); + } + + if (item && item->type == cJSON_String && item->valuestring != NULL) { + return atoll(item->valuestring); + } + + return 0; +} + +static tagTime MakeTagTimeFromMs(long long ms) +{ + time_t sec = static_cast(ms / 1000); + struct tm tmv; + #ifdef _WIN32 + localtime_s(&tmv, &sec); + #else + localtime_r(&sec, &tmv); + #endif + return tagTime(tmv); +} + +// connectionType: 0=星型, 1=角型 +std::array BuildPqFloatDataFromJson(cJSON* jsondata, + int connectionType) +{ + std::array all_data; + + const char* PH3[3]; + const char* PH4[4]; + + if (connectionType == 1) { + // 角型 + PH3[0] = "AB"; + PH3[1] = "BC"; + PH3[2] = "CA"; + + PH4[0] = "AB"; + PH4[1] = "BC"; + PH4[2] = "CA"; + PH4[3] = "T"; + } + else { + // 星型 + PH3[0] = "A"; + PH3[1] = "B"; + PH3[2] = "C"; + + PH4[0] = "A"; + PH4[1] = "B"; + PH4[2] = "C"; + PH4[3] = "T"; + } + + long long timeMs = GetJsonTimeMs(jsondata); + + for (int stat = 0; stat < 4; ++stat) { + tagPqData_Float& dst = all_data[stat]; + + dst.name = 0; + dst.Data_Type = 0; + + if (timeMs > 0) { + dst.time = MakeTagTimeFromMs(timeMs); + } + + // 1. Rms[0..8] + // 0-2: 相电压有效值 VRMS + // 3-5: 相电流有效值 IRMS + // 6-8: 线电压有效值 VRMS_LVR + // 注意:根据 ZJ.xml/jsondata,只有线电压有效值使用 LVR + if (connectionType == 1) { + // 角型 + + // 相电压空置 + dst.Rms[0] = EMPTY_FLOAT_VALUE; + dst.Rms[1] = EMPTY_FLOAT_VALUE; + dst.Rms[2] = EMPTY_FLOAT_VALUE; + + // 电流 + for (int i = 0; i < 3; ++i) { + dst.Rms[i + 3] = + GetValue(jsondata, stat, "I", PH3[i], "IRMS"); + } + + // 线电压 + for (int i = 0; i < 3; ++i) { + dst.Rms[i + 6] = + GetValue(jsondata, stat, "V", PH3[i], "VRMS_LVR"); + } + } + else { + // 星型 + + // 相电压 + for (int i = 0; i < 3; ++i) { + dst.Rms[i] = + GetValue(jsondata, stat, "V", PH3[i], "VRMS"); + } + + // 电流 + for (int i = 0; i < 3; ++i) { + dst.Rms[i + 3] = + GetValue(jsondata, stat, "I", PH3[i], "IRMS"); + } + + // 线电压 + for (int i = 0; i < 3; ++i) { + dst.Rms[i + 6] = + GetValue(jsondata, stat, "V", PH3[i], "VRMS_LVR"); + } + } + + // 2. 电压偏差 + // 星型:转换函数取 UU/UL[0..2] 作为相电压偏差,线电压偏差空置 + // 角型:转换函数前 3 个位置空置,后面取 UU/UL[0..2] 作为线电压偏差 + // 因为 jsondata 里没有 DELTA_V_LVR,所以统一填 DELTA_V 到 [0..2] + for (int i = 0; i < 3; ++i) { + float dev = GetValue(jsondata, stat, "V", PH3[i], "DELTA_V"); + FillDeviation(dev, dst.UU_Deviation[i], dst.UL_Deviation[i]); + } + + // 3. 频率偏差 + 频率 + dst.F_Deviation[0] = GetValue(jsondata, stat, "V", "T", "DELTA_FREQ"); + dst.F_Deviation[1] = GetValue(jsondata, stat, "V", "T", "FREQ"); + + // 4. UI_Seq + dst.UI_Seq[0][0] = GetValue(jsondata, stat, "V", "T", "VZSEQ"); + dst.UI_Seq[0][1] = GetValue(jsondata, stat, "V", "T", "VNSEQ"); + dst.UI_Seq[0][2] = GetValue(jsondata, stat, "V", "T", "VPSEQ"); + dst.UI_Seq[0][3] = GetValue(jsondata, stat, "V", "T", "V_UNBAN"); + + dst.UI_Seq[1][0] = GetValue(jsondata, stat, "I", "T", "IZSEQ"); + dst.UI_Seq[1][1] = GetValue(jsondata, stat, "I", "T", "INSEQ"); + dst.UI_Seq[1][2] = GetValue(jsondata, stat, "I", "T", "IPSEQ"); + dst.UI_Seq[1][3] = GetValue(jsondata, stat, "I", "T", "I_UNBAN"); + + // 5. 基波有效值 FuHarm[*][0] + // 星型:FuHarm[0..2][0] 被当作 A/B/C 相电压 V1 + // 角型:FuHarm[0..2][0] 被当作 AB/BC/CA 线电压 V1 + // jsondata 中仍然使用 V1 字段,不额外使用 LVR + for (int i = 0; i < 3; ++i) { + dst.FuHarm[i][0] = GetValue(jsondata, stat, "V", PH3[i], "V1"); + dst.FuHarm[i + 3][0] = GetValue(jsondata, stat, "I", PH3[i], "I1"); + } + + // 6. 基波相角 FuHarmPhase[*][0] + for (int i = 0; i < 3; ++i) { + dst.FuHarmPhase[i][0] = + GetValue(jsondata, stat, "V", PH3[i], "VFUND_ANGLE"); + + dst.FuHarmPhase[i + 3][0] = + GetValue(jsondata, stat, "I", PH3[i], "IFUND_ANGLE"); + } + + // 7. 2-50 次谐波有效值 + // 星型转换:先取 FuHarm[0..2][1..49] 作为相电压,再取 FuHarm[3..5] 作为电流,线电压空置 + // 角型转换:先空置相电压,再取 FuHarm[3..5] 作为电流,再取 FuHarm[0..2] 作为线电压 + // 所以这里统一填 FuHarm[0..2]=V2..V50,FuHarm[3..5]=I2..I50 + for (int h = 1; h < HARMNUM; ++h) { + int no = h + 1; + + for (int i = 0; i < 3; ++i) { + dst.FuHarm[i][h] = + GetValue(jsondata, stat, "V", PH3[i], "V" + std::to_string(no)); + + dst.FuHarm[i + 3][h] = + GetValue(jsondata, stat, "I", PH3[i], "I" + std::to_string(no)); + } + } + + // 8. 2-50 次谐波相角 + for (int h = 1; h < HARMNUM; ++h) { + int no = h + 1; + + for (int i = 0; i < 3; ++i) { + dst.FuHarmPhase[i][h] = + GetValue(jsondata, stat, "V", PH3[i], "VA" + std::to_string(no)); + + dst.FuHarmPhase[i + 3][h] = + GetValue(jsondata, stat, "I", PH3[i], "IA" + std::to_string(no)); + } + } + + // 9. 间谐波有效值 InHarm[*][0..49] + // 星型:InHarm[0..2] 相电压有效,InHarm[3..5] 电流有效,线电压空置 + // 角型:先空置相电压,再取 InHarm[3..5] 电流,再取 InHarm[0..2] 线电压 + // jsondata 中统一使用 SV_x / SI_x + for (int h = 0; h < HARMNUM; ++h) { + for (int i = 0; i < 3; ++i) { + dst.InHarm[i][h].Val = + GetValue(jsondata, stat, "V", PH3[i], "SV_" + std::to_string(h)); + + dst.InHarm[i + 3][h].Val = + GetValue(jsondata, stat, "I", PH3[i], "SI_" + std::to_string(h)); + } + } + + // 10. 总功率 Total_Power[4][3] + // phase: A/B/C/T + // index: 0=P, 1=Q, 2=S + for (int i = 0; i < 4; ++i) { + dst.Total_Power[i][0] = GetValue(jsondata, stat, "PQ", PH4[i], "P"); + dst.Total_Power[i][1] = GetValue(jsondata, stat, "PQ", PH4[i], "Q"); + dst.Total_Power[i][2] = GetValue(jsondata, stat, "PQ", PH4[i], "S"); + } + + // 11. 谐波功率 Harm_Power[4][50] + // h=0 对应 P1/Q1/S1,h=1..49 对应 P2..P50/Q2..Q50/S2..S50 + for (int i = 0; i < 4; ++i) { + for (int h = 0; h < HARMNUM; ++h) { + int no = h + 1; + + dst.Harm_Power[i][h].P = + GetValue(jsondata, stat, "PQ", PH4[i], "P" + std::to_string(no)); + + dst.Harm_Power[i][h].Q = + GetValue(jsondata, stat, "PQ", PH4[i], "Q" + std::to_string(no)); + + dst.Harm_Power[i][h].S = + GetValue(jsondata, stat, "PQ", PH4[i], "S" + std::to_string(no)); + } + } + + // 12. 谐波含有率 Harm_Contain[6][50] + // 0-2: 电压谐波含有率 + // 3-5: 电流谐波含有率 + // 转换函数会根据星型/角型决定这些数据输出到相电压区还是线电压区 + for (int h = 1; h < HARMNUM; ++h) { + for (int i = 0; i < 3; ++i) { + dst.Harm_Contain[i][h] = + GetValue(jsondata, stat, "V", PH3[i], "SV_" + std::to_string(h)); + + dst.Harm_Contain[i + 3][h] = + GetValue(jsondata, stat, "I", PH3[i], "SI_" + std::to_string(h)); + } + } + + // 13. 谐波总畸变率 Harm_Aberrance[6] + // 0-2: 电压 THD + // 3-5: 电流 THD + for (int i = 0; i < 3; ++i) { + dst.Harm_Aberrance[i] = + GetValue(jsondata, stat, "V", PH3[i], "VTHD"); + + dst.Harm_Aberrance[i + 3] = + GetValue(jsondata, stat, "I", PH3[i], "ITHD"); + } + + // 14. 功率因数 + for (int i = 0; i < 4; ++i) { + dst.Cos_PF[i] = GetValue(jsondata, stat, "PQ", PH4[i], "PF"); + dst.Cos_DF[i] = GetValue(jsondata, stat, "PQ", PH4[i], "DF"); + } + + // 15. 波动、短闪、长闪 + // 目前 jsondata 中没有 LVR 字段,统一填 A/B/C 三相字段 + // 星型转换函数输出三相数据,线电压位置空置 + // 角型转换函数先空置三相位置,再把这三个值输出到线电压位置 + for (int i = 0; i < 3; ++i) { + dst.U_Fluctuation[i] = GetValue(jsondata, stat, "V", PH3[i], "FLUC"); + dst.U_Flicker[i] = GetValue(jsondata, stat, "V", PH3[i], "PST"); + dst.UL_Flicker[i] = GetValue(jsondata, stat, "V", PH3[i], "PLT"); + } + } + + return all_data; +} + +////////////////////////////////////////////////////实时部分 + +static float GetRtJsonFloat(cJSON* root, + const char* group, + const char* phase, + const std::string& key) +{ + cJSON* value = GetObj(root, "Value"); + cJSON* g = GetObj(value, group); + cJSON* p = GetObj(g, phase); + cJSON* item = GetObj(p, key.c_str()); + + if (item == NULL) { + return 0.0f; + } + + if (item && item->type == cJSON_Number) { + return static_cast(item->valuedouble); + } + + if (item && item->type == cJSON_String && item->valuestring != NULL) { + return static_cast(atof(item->valuestring)); + } + + return 0.0f; +} + +static float GetRtValue(cJSON* root, + const char* group, + const char* phase, + const std::string& key) +{ + return GetRtJsonFloat(root, group, phase, key); +} + +static long long GetRtJsonTimeMs(cJSON* root) +{ + cJSON* value = GetObj(root, "Value"); + cJSON* item = GetObj(value, "TIME"); + + if (item == NULL) { + return 0; + } + + if (item && item->type == cJSON_Number) { + return static_cast(item->valuedouble); + } + + if (item && item->type == cJSON_String && item->valuestring != NULL) { + return atoll(item->valuestring); + } + + return 0; +} + +static tagTime MakeRtTagTimeFromMs(long long ms) +{ + time_t sec = static_cast(ms / 1000); + struct tm tmv; + #ifdef _WIN32 + localtime_s(&tmv, &sec); + #else + localtime_r(&sec, &tmv); + #endif + return tagTime(tmv); +} + +static void FillRtDeviation(float val, float& up, float& low) +{ + if (val >= 0.0f) { + up = val; + low = 0.0f; + } else { + up = 0.0f; + low = -val; + } +} + +// wiringType: 0=星型, 1=角型 +RealtagPqDate_float BuildRealPqDataFromJson(cJSON* jsondata, int wiringType) +{ + RealtagPqDate_float realdata; + + const bool isDelta = (wiringType == 1); + + const char* PH3[3]; + const char* PH4[4]; + + if (isDelta) { + PH3[0] = "AB"; + PH3[1] = "BC"; + PH3[2] = "CA"; + + PH4[0] = "AB"; + PH4[1] = "BC"; + PH4[2] = "CA"; + PH4[3] = "T"; + } else { + PH3[0] = "A"; + PH3[1] = "B"; + PH3[2] = "C"; + + PH4[0] = "A"; + PH4[1] = "B"; + PH4[2] = "C"; + PH4[3] = "T"; + } + + long long timeMs = GetRtJsonTimeMs(jsondata); + if (timeMs > 0) { + realdata.time = MakeRtTagTimeFromMs(timeMs); + } + + // 1. Rms[0..8] + // 实时结构注释:相电压、线电压、电流有效值 + if (isDelta) { + // 角型:相电压空置,线电压从 AB/BC/CA 的 VRMS 取,电流也按 AB/BC/CA 取 + for (int i = 0; i < 3; ++i) { + realdata.Rms[i] = EMPTY_FLOAT_VALUE; + realdata.Rms[i + 3] = GetRtValue(jsondata, "V", PH3[i], "VRMS"); + realdata.Rms[i + 6] = GetRtValue(jsondata, "I", PH3[i], "IRMS"); + } + } else { + // 星型:相电压 A/B/C VRMS,线电压 A/B/C VRMS_LVR,电流 A/B/C IRMS + for (int i = 0; i < 3; ++i) { + realdata.Rms[i] = GetRtValue(jsondata, "V", PH3[i], "VRMS"); + realdata.Rms[i + 3] = GetRtValue(jsondata, "V", PH3[i], "VRMS_LVR"); + realdata.Rms[i + 6] = GetRtValue(jsondata, "I", PH3[i], "IRMS"); + } + } + + // 2. 电压偏差 + // 星型序列化取 9-11 为相电压偏差;角型序列化 12-14 为线电压偏差。 + // 两种最终都从 UU/UL[0..2] 取,所以填 [0..2] 即可。 + for (int i = 0; i < 3; ++i) { + float dev = GetRtValue(jsondata, "V", PH3[i], "DELTA_V"); + FillRtDeviation(dev, realdata.UU_Deviation[i], realdata.UL_Deviation[i]); + } + + // 3. THD[0..5] + // 星型:THD[0..2] 相电压,THD[3..5] 电流 + // 角型:THD[0..2] 填线电压;Delta_RtHarmV 也取 0..2 + for (int i = 0; i < 3; ++i) { + realdata.THD[i] = GetRtValue(jsondata, "V", PH3[i], "VTHD"); + realdata.THD[i + 3] = GetRtValue(jsondata, "I", PH3[i], "ITHD"); + } + + // 4. FREQ[0..1] + realdata.FREQ[0] = GetRtValue(jsondata, "V", "T", "FREQ"); + realdata.FREQ[1] = GetRtValue(jsondata, "V", "T", "DELTA_FREQ"); + + // 5. UI_Seq[2][5] + // 序列化时输出 [0][0,1,2,4] 和 [1][0,1,2,4],所以 [3] 可放零序不平衡备用,[4] 放负序不平衡 + realdata.UI_Seq[0][0] = GetRtValue(jsondata, "V", "T", "VZSEQ"); + realdata.UI_Seq[0][1] = GetRtValue(jsondata, "V", "T", "VNSEQ"); + realdata.UI_Seq[0][2] = GetRtValue(jsondata, "V", "T", "VPSEQ"); + realdata.UI_Seq[0][3] = GetRtValue(jsondata, "V", "T", "VZSEQ_UNBAN"); + realdata.UI_Seq[0][4] = GetRtValue(jsondata, "V", "T", "V_UNBAN"); + + realdata.UI_Seq[1][0] = GetRtValue(jsondata, "I", "T", "IZSEQ"); + realdata.UI_Seq[1][1] = GetRtValue(jsondata, "I", "T", "INSEQ"); + realdata.UI_Seq[1][2] = GetRtValue(jsondata, "I", "T", "IPSEQ"); + realdata.UI_Seq[1][3] = GetRtValue(jsondata, "I", "T", "IZSEQ_UNBAN"); + realdata.UI_Seq[1][4] = GetRtValue(jsondata, "I", "T", "I_UNBAN"); + + // 6. TOTAL_POWER[4][3], COS_PF, COS_DF + for (int i = 0; i < 4; ++i) { + realdata.TOTAL_POWER[i][0] = GetRtValue(jsondata, "PQ", PH4[i], "P"); + realdata.TOTAL_POWER[i][1] = GetRtValue(jsondata, "PQ", PH4[i], "Q"); + realdata.TOTAL_POWER[i][2] = GetRtValue(jsondata, "PQ", PH4[i], "S"); + + realdata.COS_PF[i] = GetRtValue(jsondata, "PQ", PH4[i], "PF"); + realdata.COS_DF[i] = GetRtValue(jsondata, "PQ", PH4[i], "DF"); + } + + // 7. 基波有效值和基波相角 + // HARMV/HARMI/HARMVP/HARMIP 的 [0] 被序列化函数当作基波 V1/I1 和基波角度。 + for (int i = 0; i < 3; ++i) { + realdata.HARMV[i][0] = GetRtValue(jsondata, "V", PH3[i], "V1"); + realdata.HARMI[i][0] = GetRtValue(jsondata, "I", PH3[i], "I1"); + + realdata.HARMVP[i][0] = GetRtValue(jsondata, "V", PH3[i], "VFUND_ANGLE"); + + // 实时 JSON 中电流基波相角字段是 I_ANGLE + realdata.HARMIP[i][0] = GetRtValue(jsondata, "I", PH3[i], "I_ANGLE"); + } + + // 8. 2~50 次谐波、电压/电流相角 + for (int h = 1; h < HARMNUM; ++h) { + int no = h + 1; + + for (int i = 0; i < 3; ++i) { + realdata.HARMV[i][h] = + GetRtValue(jsondata, "V", PH3[i], "V" + std::to_string(no)); + + realdata.HARMI[i][h] = + GetRtValue(jsondata, "I", PH3[i], "I" + std::to_string(no)); + + realdata.HARMVP[i][h] = + GetRtValue(jsondata, "V", PH3[i], "VA" + std::to_string(no)); + + // 如果以后 JSON 有 IA2~IA50,这里会自动取;当前样例没有则为 0 + realdata.HARMIP[i][h] = + GetRtValue(jsondata, "I", PH3[i], "IA" + std::to_string(no)); + } + } + + // 9. 间谐波电压 INHARMV[3][50] + for (int h = 0; h < HARMNUM; ++h) { + for (int i = 0; i < 3; ++i) { + realdata.INHARMV[i][h] = + GetRtValue(jsondata, "V", PH3[i], "SV_" + std::to_string(h)); + } + } + + return realdata; +} + +///////////////////////////////////////////////////////通用方式,根据不同的模板到pqd查找名称建立映射然后到json中取值填入再序列化输出 +struct PqdMeta { + int idx; + std::string name; + std::string phase; + int harmStart; + int harmEnd; + + PqdMeta() : idx(-1), harmStart(0), harmEnd(0) {} +}; + +static int GetInt(cJSON* obj, const char* name, int defVal = 0) +{ + cJSON* item = GetObj(obj, name); + if (!item) return defVal; + if (item->type == cJSON_Number) return item->valueint; + if (item->type == cJSON_String && item->valuestring) return atoi(item->valuestring); + return defVal; +} + +static std::string GetStr(cJSON* obj, const char* name) +{ + cJSON* item = GetObj(obj, name); + if (item && item->type == cJSON_String && item->valuestring) { + return item->valuestring; + } + return ""; +} + +static float GetJsonFloat(cJSON* root, + const std::string& group, + const std::string& phase, + const std::string& key) +{ + cJSON* value = GetObj(root, "Value"); + cJSON* g = GetObj(value, group.c_str()); + cJSON* p = GetObj(g, phase.c_str()); + cJSON* item = GetObj(p, key.c_str()); + + if (!item) return 0.0f; + + if (item->type == cJSON_Number) { + return static_cast(item->valuedouble); + } + + if (item->type == cJSON_String && item->valuestring) { + return static_cast(atof(item->valuestring)); + } + + return 0.0f; +} + +static std::string Base64Encode(const unsigned char* bytes_to_encode, size_t in_len) +{ + static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; i < 4; i++) { + ret += base64_chars[char_array_4[i]]; + } + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + char_array_3[j] = '\0'; + } + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; j < i + 1; j++) { + ret += base64_chars[char_array_4[j]]; + } + + while (i++ < 3) { + ret += '='; + } + } + + return ret; +} + +static std::string FloatBufferToBase64(const std::vector& buffer) +{ + const unsigned char* data = + reinterpret_cast(buffer.data()); + + return Base64Encode(data, buffer.size() * sizeof(float)); +} + +static std::map BuildPqdMetaMap(cJSON* tplRoot) +{ + std::map result; + + cJSON* pqdArr = GetObj(tplRoot, "Pqd"); + if (!pqdArr || !pqdArr->type == cJSON_Array){ + return result; + } + + int size = cJSON_GetArraySize(pqdArr); + for (int i = 0; i < size; ++i) { + cJSON* item = cJSON_GetArrayItem(pqdArr, i); + if (!item) continue; + + PqdMeta meta; + meta.idx = GetInt(item, "Idx", -1); + meta.name = GetStr(item, "Name"); + meta.phase = GetStr(item, "Phase"); + meta.harmStart = GetInt(item, "HarmStart", 0); + meta.harmEnd = GetInt(item, "HarmEnd", 0); + + if (meta.idx >= 0) { + result[meta.idx] = meta; + } + } + + return result; +} + +static cJSON* FindDataSet(cJSON* tplRoot, const std::string& dataSetName) +{ + cJSON* cldevArr = GetObj(tplRoot, "Cldev"); + if (!cldevArr || !cldevArr->type == cJSON_Array){ + return NULL; + } + + int cldevSize = cJSON_GetArraySize(cldevArr); + for (int i = 0; i < cldevSize; ++i) { + cJSON* cldev = cJSON_GetArrayItem(cldevArr, i); + cJSON* dsArr = GetObj(cldev, "DataSet"); + if (!dsArr || !dsArr->type == cJSON_Array){ + continue; + } + + int dsSize = cJSON_GetArraySize(dsArr); + for (int j = 0; j < dsSize; ++j) { + cJSON* ds = cJSON_GetArrayItem(dsArr, j); + std::string name = GetStr(ds, "Name"); + if (name == dataSetName) { + return ds; + } + } + } + + return NULL; +} + +static std::vector GetDataArrayIdxList(cJSON* dataSet) +{ + std::vector result; + + cJSON* arr = GetObj(dataSet, "DataArray"); + if (!arr || !arr->type == cJSON_Array) { + return result; + } + + int size = cJSON_GetArraySize(arr); + for (int i = 0; i < size; ++i) { + cJSON* item = cJSON_GetArrayItem(arr, i); + int idx = GetInt(item, "Idx", -1); + if (idx >= 0) { + result.push_back(idx); + } + } + + return result; +} + +static std::string StatPrefix(int statType) +{ + // 0=95, 1=平均, 2=最大, 3=最小 + switch (statType) { + case 0: return "G_"; + case 1: return ""; + case 2: return "MAX_"; + case 3: return "MIN_"; + default: return ""; + } +} + +static std::string MakeJsonKey(const std::string& baseKey, + bool isStat, + int statType) +{ + if (!isStat) { + return baseKey; + } + return StatPrefix(statType) + baseKey; +} + +static float GetByKey(cJSON* jsondata, + const std::string& group, + const std::string& phase, + const std::string& baseKey, + bool isStat, + int statType) +{ + return GetJsonFloat(jsondata, group, phase, + MakeJsonKey(baseKey, isStat, statType)); +} + +static void AppendHarmValues(std::vector& out, + cJSON* jsondata, + const PqdMeta& meta, + const std::string& group, + const std::string& prefix, + bool isStat, + int statType) +{ + int start = meta.harmStart; + int end = meta.harmEnd; + + if (start <= 0 && end <= 0) { + out.push_back(0.0f); + return; + } + + for (int h = start; h <= end; ++h) { + out.push_back(GetByKey(jsondata, group, meta.phase, + prefix + std::to_string(h), + isStat, statType)); + } +} + +static void AppendInHarmValues(std::vector& out, + cJSON* jsondata, + const PqdMeta& meta, + const std::string& group, + const std::string& prefix, + bool isStat, + int statType) +{ + int count = meta.harmEnd - meta.harmStart + 1; + if (count <= 0) { + count = 50; + } + + for (int i = 0; i < count; ++i) { + out.push_back(GetByKey(jsondata, group, meta.phase, + prefix + std::to_string(i), + isStat, statType)); + } +} + +static float GetSingleValueByMeta(cJSON* jsondata, + const PqdMeta& meta, + bool isStat, + int statType) +{ + const std::string& n = meta.name; + const std::string& ph = meta.phase; + + if (n == "Pq_Freq") return GetByKey(jsondata, "V", "T", "FREQ", isStat, statType); + if (n == "Pq_FreqDev") return GetByKey(jsondata, "V", "T", "DELTA_FREQ", isStat, statType); + + if (n == "Pq_RmsU") return GetByKey(jsondata, "V", ph, "VRMS", isStat, statType); + if (n == "Pq_RmsLU") return GetByKey(jsondata, "V", ph, "VRMS_LVR", isStat, statType); + if (n == "Pq_RmsI") return GetByKey(jsondata, "I", ph, "IRMS", isStat, statType); + + if (n == "Pq_RmsFundU") return GetByKey(jsondata, "V", ph, "V1", isStat, statType); + if (n == "Pq_RmsFundLU") return GetByKey(jsondata, "V", ph, "V1", isStat, statType); + if (n == "Pq_RmsFundI") return GetByKey(jsondata, "I", ph, "I1", isStat, statType); + + if (n == "Pq_UDev") return GetByKey(jsondata, "V", ph, "DELTA_V", isStat, statType); + if (n == "Pq_LUDev") return GetByKey(jsondata, "V", ph, "DELTA_V", isStat, statType); + + if (n == "Pq_FundUAng") return GetByKey(jsondata, "V", ph, "VFUND_ANGLE", isStat, statType); + if (n == "Pq_FundLUAng") return GetByKey(jsondata, "V", ph, "VFUND_ANGLE", isStat, statType); + if (n == "Pq_FundIAng") return GetByKey(jsondata, "I", ph, "I_ANGLE", isStat, statType); + + if (n == "Pq_ThdU") return GetByKey(jsondata, "V", ph, "VTHD", isStat, statType); + if (n == "Pq_ThdLU") return GetByKey(jsondata, "V", ph, "VTHD", isStat, statType); + if (n == "Pq_ThdI") return GetByKey(jsondata, "I", ph, "ITHD", isStat, statType); + + if (n == "Pq_SeqZeroU") return GetByKey(jsondata, "V", "T", "VZSEQ", isStat, statType); + if (n == "Pq_SeqNegU") return GetByKey(jsondata, "V", "T", "VNSEQ", isStat, statType); + if (n == "Pq_SeqPosU") return GetByKey(jsondata, "V", "T", "VPSEQ", isStat, statType); + if (n == "Pq_UnbalNegU") return GetByKey(jsondata, "V", "T", "V_UNBAN", isStat, statType); + if (n == "Pq_UnbalZeroU") return GetByKey(jsondata, "V", "T", "VZSEQ_UNBAN", isStat, statType); + + if (n == "Pq_SeqZeroI") return GetByKey(jsondata, "I", "T", "IZSEQ", isStat, statType); + if (n == "Pq_SeqNegI") return GetByKey(jsondata, "I", "T", "INSEQ", isStat, statType); + if (n == "Pq_SeqPosI") return GetByKey(jsondata, "I", "T", "IPSEQ", isStat, statType); + if (n == "Pq_UnbalNegI") return GetByKey(jsondata, "I", "T", "I_UNBAN", isStat, statType); + if (n == "Pq_UnbalZeroI") return GetByKey(jsondata, "I", "T", "IZSEQ_UNBAN", isStat, statType); + + if (n == "Pq_P") return GetByKey(jsondata, "PQ", ph, "P", isStat, statType); + if (n == "Pq_Q") return GetByKey(jsondata, "PQ", ph, "Q", isStat, statType); + if (n == "Pq_S") return GetByKey(jsondata, "PQ", ph, "S", isStat, statType); + + if (n == "Pq_TotP") return GetByKey(jsondata, "PQ", "T", "P", isStat, statType); + if (n == "Pq_TotQ") return GetByKey(jsondata, "PQ", "T", "Q", isStat, statType); + if (n == "Pq_TotS") return GetByKey(jsondata, "PQ", "T", "S", isStat, statType); + + if (n == "Pq_PF") return GetByKey(jsondata, "PQ", ph, "PF", isStat, statType); + if (n == "Pq_DF") return GetByKey(jsondata, "PQ", ph, "DF", isStat, statType); + if (n == "Pq_TotPF") return GetByKey(jsondata, "PQ", "T", "PF", isStat, statType); + if (n == "Pq_TotDF") return GetByKey(jsondata, "PQ", "T", "DF", isStat, statType); + + if (n == "Pq_Fluct") return GetByKey(jsondata, "V", ph, "FLUC", isStat, statType); + if (n == "Pq_LFluct") return GetByKey(jsondata, "V", ph, "FLUC", isStat, statType); + if (n == "Pq_Pst") return GetByKey(jsondata, "V", ph, "PST", isStat, statType); + if (n == "Pq_LPst") return GetByKey(jsondata, "V", ph, "PST", isStat, statType); + if (n == "Pq_Plt") return GetByKey(jsondata, "V", ph, "PLT", isStat, statType); + if (n == "Pq_LPlt") return GetByKey(jsondata, "V", ph, "PLT", isStat, statType); + + return 0.0f; +} + +static void AppendValueByMeta(std::vector& out, + cJSON* jsondata, + const PqdMeta& meta, + bool isStat, + int statType) +{ + const std::string& n = meta.name; + + if (n == "Pq_HarmU" || n == "Pq_HarmLU") { + AppendHarmValues(out, jsondata, meta, "V", "V", isStat, statType); + return; + } + + if (n == "Pq_HarmI") { + AppendHarmValues(out, jsondata, meta, "I", "I", isStat, statType); + return; + } + + if (n == "Pq_HarmUAng" || n == "Pq_HarmLUAng") { + AppendHarmValues(out, jsondata, meta, "V", "VA", isStat, statType); + return; + } + + if (n == "Pq_HarmIAng") { + AppendHarmValues(out, jsondata, meta, "I", "IA", isStat, statType); + return; + } + + if (n == "Pq_InHarmUR" || n == "Pq_InHarmLU") { + AppendInHarmValues(out, jsondata, meta, "V", "SV_", isStat, statType); + return; + } + + if (n == "Pq_InHarmIAmp") { + AppendInHarmValues(out, jsondata, meta, "I", "SI_", isStat, statType); + return; + } + + if (n == "Pq_HarmP" || n == "Pq_FundP" || n == "Pq_TotHarmP") { + AppendHarmValues(out, jsondata, meta, "PQ", "P", isStat, statType); + return; + } + + if (n == "Pq_HarmQ" || n == "Pq_FundQ" || n == "Pq_TotHarmQ") { + AppendHarmValues(out, jsondata, meta, "PQ", "Q", isStat, statType); + return; + } + + if (n == "Pq_HarmS" || n == "Pq_FundS" || n == "Pq_TotHarmS") { + AppendHarmValues(out, jsondata, meta, "PQ", "S", isStat, statType); + return; + } + + out.push_back(GetSingleValueByMeta(jsondata, meta, isStat, statType)); +} + +// dataSetName 示例: +// "Ds$Pqd$Rt$01" +// "Ds$Pqd$Rt$HarmV$01" +// "Ds$Pqd$Stat$01" +std::string BuildBase64ByTemplate(cJSON* templateRoot, + cJSON* jsondata, + const std::string& dataSetName, + bool isStat, + int statType) +{ + std::map metaMap = BuildPqdMetaMap(templateRoot); + + cJSON* dataSet = FindDataSet(templateRoot, dataSetName); + if (!dataSet) { + return ""; + } + + std::vector idxList = GetDataArrayIdxList(dataSet); + + std::vector floatBuffer; + floatBuffer.reserve(2048); + + for (size_t i = 0; i < idxList.size(); ++i) { + int idx = idxList[i]; + + std::map::const_iterator it = metaMap.find(idx); + if (it == metaMap.end()) { + floatBuffer.push_back(0.0f); + continue; + } + + AppendValueByMeta(floatBuffer, jsondata, it->second, isStat, statType); + } + + return FloatBufferToBase64(floatBuffer); +} + +/////////////////////////////////////////////////////////////////////////////////////发送函数 +///////////////////////////////////////////////////////////////////////////////////////上送数据的json格式 +// 单条 DataArray 数据 +struct DataArrayItem { + int DataAttr; + time_t DataTimeSec; + time_t DataTimeUSec; + int DataTag; + std::string Data; +}; + +// Msg 对象 +struct MsgObj { + int Cldid; + int DataType; + int DataAttr; + int DsNameIdx; + std::vector DataArray; +}; + +// 整体 +struct FullObj { + std::string mac; + int Mid; + int Did; + int Pri; + int Type; + MsgObj Msg; +}; + +// DataArrayItem -> cJSON +static cJSON* DataArrayItemToJson(const DataArrayItem& d) +{ + cJSON* j = cJSON_CreateObject(); + + cJSON_AddNumberToObject(j, "dataAttr", d.DataAttr); + cJSON_AddNumberToObject(j, "dataTimeSec", (double)d.DataTimeSec); + cJSON_AddNumberToObject(j, "dataTimeUSec", (double)d.DataTimeUSec); + cJSON_AddNumberToObject(j, "dataTag", d.DataTag); + cJSON_AddStringToObject(j, "data", d.Data.c_str()); + + return j; +} + +// MsgObj -> cJSON +static cJSON* MsgObjToJson(const MsgObj& m) +{ + cJSON* j = cJSON_CreateObject(); + + cJSON_AddNumberToObject(j, "clDid", m.Cldid); + cJSON_AddNumberToObject(j, "dataType", m.DataType); + cJSON_AddNumberToObject(j, "dataAttr", m.DataAttr); + cJSON_AddNumberToObject(j, "dsNameIdx", m.DsNameIdx); + + // dataArray + cJSON* arr = cJSON_CreateArray(); + + for (size_t i = 0; i < m.DataArray.size(); ++i) { + cJSON_AddItemToArray( + arr, + DataArrayItemToJson(m.DataArray[i])); + } + + cJSON_AddItemToObject(j, "dataArray", arr); + + return j; +} + +// FullObj -> cJSON +static cJSON* FullObjToJson(const FullObj& f) +{ + cJSON* j = cJSON_CreateObject(); + + cJSON_AddStringToObject(j, "id", f.mac.c_str()); + + cJSON_AddNumberToObject(j, "mid", f.Mid); + cJSON_AddNumberToObject(j, "did", f.Did); + cJSON_AddNumberToObject(j, "pri", f.Pri); + cJSON_AddNumberToObject(j, "type", f.Type); + + cJSON_AddItemToObject(j, "msg", + MsgObjToJson(f.Msg)); + + return j; +} + +std::string generate_json( + const std::string mac, + int Mid, + int Did, + int Pri, + int Type, + int Cldid, + int DataType, + int DataAttr, + int DsNameIdx, + const std::vector& dataArray +) +{ + FullObj fobj; + + fobj.mac = mac; + fobj.Mid = Mid; + fobj.Did = Did; + fobj.Pri = Pri; + fobj.Type = Type; + + fobj.Msg.Cldid = Cldid; + fobj.Msg.DataType = DataType; + fobj.Msg.DataAttr = DataAttr; + fobj.Msg.DsNameIdx = DsNameIdx; + fobj.Msg.DataArray = dataArray; + + // 转 cJSON + cJSON* root = FullObjToJson(fobj); + + // 输出 json 字符串 + char* jsonStr = cJSON_PrintUnformatted(root); + + std::string result; + + if (jsonStr != NULL) { + result = jsonStr; + free(jsonStr); + } + + cJSON_Delete(root); + + return result; +} + +//时间转换函数 +time_t ConvertToTimestamp(const tagTime& time) { + struct tm t = {}; + t.tm_year = time.DeviceYear - 1900; // tm_year 从 1900 开始计 + t.tm_mon = time.DeviceMonth - 1; // tm_mon 从 0(1月)开始 + t.tm_mday = time.DeviceDay; + t.tm_hour = time.DeviceHour; + t.tm_min = time.DeviceMinute; + t.tm_sec = time.DeviceSecond; + + // 返回时间戳(本地时间) + return mktime(&t); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////实时数据封装发送 +void enqueue_realtime_pq(const RealtagPqDate_float& realdata, + int nPTType, + unsigned char cid, + const std::string& mac, + const std::string& mpid, + int idx) +{ + // 先根据 devIdxMap 的配置决定编码分支: + // 2: 基础数据 3: 谐波电压含有率 4: 谐波电流有效值 5: 间谐波电压含有率 + std::string base64; + + // 这里尝试用 mac 作为 key 获取 idx;如果项目里 devIdxMap 的 key 不是 mac, + // 你可以把这里改成对应的设备 id(devid)。未命中则再尝试用规范化后的 mac。 + switch (idx) { + case 2: // 基础数据(根据接线方式选择转换方法 数据全集解析) + base64 = realdata.ConvertToBase64(nPTType); + break; + case 3: // 谐波电压含有率 + base64 = realdata.ConvertToBase64_RtHarmV(nPTType); + break; + case 4: // 谐波电流有效值(幅值) + base64 = realdata.ConvertToBase64_RtHarmI(); + break; + case 5: // 间谐波电压含有率 + base64 = realdata.ConvertToBase64_RtInHarmV(); + break; + default: + // 未知 idx,回退到基础数据 + base64 = realdata.ConvertToBase64(nPTType); + break; + } else { + // 未配置 idx,回退到基础数据 + base64 = realdata.ConvertToBase64(nPTType); + } + //std::cout << base64 << std::endl; + + //lnk实时数据使用接口发送20250711 + time_t data_time = ConvertToTimestamp(realdata.time); + + std::vector arr; + arr.push_back({1, //数据属性 -1-无, 0-“Rt”,1-“Max”,2-“Min”,3-“Avg”,4-“Cp95” + data_time, //数据转换出来的时间,数据时标,相对1970年的秒,无效填入“-1” + 0, //数据时标,微秒钟,无效填入“-1” + 0, //数据标识,1-标识数据异常 + base64}); + std::string js = generate_json( + mac, //设备唯一标识,规范化后的MAC地址,如“001122334455”,不带分隔符,字母大写 + -1, //需应答的报文订阅者收到后需以此ID应答,无需应答填入“-1” + 1, //设备唯一标识Ldid,填入0代表Ndid,后续根据商议决定填id还是数字 + 1, //报文处理的优先级:1 I类紧急请求/响应 2 II类紧急请求/响应 3 普通请求/响应 4 广播报文 + 0x1302, //设备数据主动上送的数据类型 + cid, //逻辑子设备ID,0-逻辑设备本身,无填-1 + 0x04, //数据类型固定为电能质量数据 + 1, //数据属性:无“0”、实时“1”、统计“2”等 + idx, //数据集序号(以数据集方式上送),无填-1 + arr //数据数组 + ); + //std::cout << js << std::en + Ckafka_data_t data; + data.monitor_id = 1; //上送的实时数据没有测点序号,统一填1 + data.strTopic = TOPIC_RTDATA; //实时topic + data.strText = js; + data.mp_id = mpid; //监测点id + + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(data); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 +} + +////////////////////////////////////////////////////////////////////////////////统计数据打包发送 + +// 封装:组装统计数据并入队发送 +void enqueue_stat_pq(const std::string& max_base64Str, + const std::string& min_base64Str, + const std::string& avg_base64Str, + const std::string& cp95_base64Str, + time_t data_time, + const std::string& mac, + short cid, + const std::string& mpid) +{ + std::vector arr; + arr.push_back({1, //数据属性 -1-无, 0-“Rt”,1-“Max”,2-“Min”,3-“Avg”,4-“Cp95” + data_time, //数据转换出来的时间,数据时标,相对1970年的秒,无效填入“-1” + 0, //数据时标,微秒钟,无效填入“-1” + 0, //数据标识,1-标识数据异常 + max_base64Str}); + arr.push_back({2, data_time, 0, 0, min_base64Str}); + arr.push_back({3, data_time, 0, 0, avg_base64Str}); + arr.push_back({4, data_time, 0, 0, cp95_base64Str}); + + std::string js = generate_json( + normalize_mac(mac), + -1, //需应答的报文订阅者收到后需以此ID应答,无需应答填入“-1” + 1, //设备唯一标识Ldid,填入0代表Ndid,后续根据商议决定填id还是数字 + 1, //报文处理的优先级:1 I类紧急请求/响应 2 II类紧急请求/响应 3 普通请求/响应 4 广播报文 + 0x1302, //设备数据主动上送的数据类型 + cid, //逻辑子设备ID,0-逻辑设备本身,无填-1(原:avg_data.name) + 0x04, //数据类型固定为电能质量 + 2, //数据属性:无“0”、实时“1”、统计“2”等 + 1, //数据集序号(以数据集方式上送),无填-1 + arr //数据数组 + ); + + //std::cout << js << std::endl; + + Ckafka_data_t data; + data.monitor_no = cid; //监测点序号(原:avg_data.name) + data.strTopic = TOPIC_STAT;//统计topic + data.strText = js; + data.mp_id = mpid; //监测点id + + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(data); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 + + std::cout << "Successfully assembled tagPqData for line: " + << cid << std::endl; +} + +//////////////////////////////////////////////////////////////////////////////////// +//以下仅估计开发时间,不包括代码编译调试和测试 +/*后续接入云平台,云平台需要根据61850协议进行台账下发:需要对比云和微服务的台账差异,看是否能统一,各取所需 一天 +实时数据请求需要添加参数处理,idx区分数据集 半天 +补招逻辑有差异,61850是全补招,云是事件和稳态分开,补招下发按照61850的来 徐扬添加 +暂态上送逻辑基本一致,对比接口上送数据即可 半天 +云需要添加映射文件接口给61850使用 徐扬添加 +台账变更逻辑一样,对比台账看是否能统一 一天 +请求响应、装置连接状态、前置心跳、文件上传、文件下载、文件传输、读取文件目录、文件删除、装置重启指令的处理逻辑基本一致需要对比交互json,下发的要根据61850需求来,部分肯定需要修改 五天 +日志上传方案基本一致,代码基本一致,但是上送日志内容可能不一样,可以不修改 +mq主题云前置有cloudtopic用于装置控制,61850是filetopic,按照61850的来 徐扬添加针对61850的装置控制逻辑 +进程控制要按照61850的来,徐扬添加 +上传下载接口基本一致 +要添加61850到云的指标映射关系 二天 +要添加动态云模板的存储(文件/内存) 和解析代码 五天+ +要添加61850数据到云数据的转换、复用代码但是代码是写死的一种模板,可以先完成,后续改动态,复用代码编写数据上送和编译测试 5天+ +当前基础的转换框架已搭建,需要基于61850当前的运行控制框架添加模板控制,数据转换控制,数据上送控制等,预计5天+ +*/ + + + + + + + diff --git a/json/PQSMsg.h b/json/PQSMsg.h new file mode 100644 index 0000000..eb07560 --- /dev/null +++ b/json/PQSMsg.h @@ -0,0 +1,2548 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include // 字节序转换 +#include +#include +using namespace std; + +// 辅助转换函数 +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; +} +// 发送报文功能码枚举 +enum class MsgRequestType : unsigned char { + //询问装置心跳 + Request_HeartBeat = 0x01, + //询问统计数据时间 + Request_StatTime = 0x8b, + //询问统计数据 + Request_Stat = 0x8a, + //询问实时数据 + Request_New_3S = 0x04, + //下载装置文件 + Request_File_Download = 0x07, + //上传装置文件 + Request_File_Send = 0x08, + //删除装置文件 + Request_File_Del = 0x09, + //目录建立 + Request_Menu_Set = 0x0b, + //目录删除 + Request_Menu_Del = 0x0c, + //询问文件目录 + Request_FileDir = 0x02, + //询问装置定值 + Request_FixValue = 0x20, + //询问装置定值描述 + Request_FixDes = 0x21, + //设置装置定值 + Request_Set_Fix = 0x22, + //询问内部定值 + Request_Read_InterFix = 0x23, + //询问内部定值描述 内部定值or控制字 + Request_Read_InterFixDes = 0x24, + //设置内部定值 + Request_Set_InterFix = 0x25, + //询问装置运行信息 + Request_Read_RunningInformation = 0x0e, + //设置装置对时 + Request_RightTime = 0x86, + //补招事件日志 + Request_Read_Event = 0x0D, + //执行控制事件 + Request_Ctrl = 0x0A, + //执行装置升级 + Request_Upgrade = 0x26 +}; +// 接收报文功能码枚举 +enum class MsgResponseType : unsigned char { + //询问装置心跳应答 + Response_HeartBeat = 0x81, + //询问统计数据时间 + Response_StatTime = 0x27, + //询问统计数据 + Response_Stat = 0x26, + //询问实时数据 + Response_New_3S = 0x84, + //主动上送的暂态事件 + Response_Event = 0x16, + //主动上送的波形文件信息事件 + Response_ActiveSOEInfo = 0x17, + //下载装置文件 + Response_File_Download = 0x87, + //上传装置文件 帧传递采用默认应答,最后一帧回复后,装置再应答一帧收全 + Response_File_Send = 0x88, + //询问文件目录 + Response_FileDir = 0x82, + //询问装置定值 + Response_FixValue = 0xA0, + //询问装置定值描述 + Response_FixDes = 0xA1, + //设置装置定值(未使用,采用默认肯定与否定应答) + Response_Set_Fix = 0xA2, + //询问内部定值 + Response_Read_InterFix = 0xA3, + //询问内部定值描述 + Response_Read_InterFixDes = 0xA4, + //设置内部定值(未使用,采用默认肯定与否定应答) + Response_Set_InterFix = 0xA5, + //询问装置运行信息 + Response_Read_RunningInformation = 0x8e, + //设置装置对时(未使用,采用默认肯定与否定应答) + Response_RightTime = 0x86, + //补招事件日志 + Response_Read_Event = 0x8D, + //执行控制事件应答 + Response_Ctrl = 0x8a, + //装置升级应答-升级数据传输采用40/41默认应答,升级执行和结束采用专用A6升级应答 + Response_Upgrade = 0xA6, + //默认肯定应答 + Response_NewACK = 0x40, + //默认否定应答 + Response_NewNACK = 0x41 +}; +//基础消息结构 +class MessageParser { +public: + // 成员变量 + uint8_t msgType; //功能码 + std::vector RecvData; //数据体 + int nMsgLen; //功能码+帧序号+数据体 + int nRecvDataLen; //数据体长度 + + // 主处理函数 - 返回bool类型 + bool SetMsg(const uint8_t* udata, size_t data_size) { + // 1. 检查空指针 + if (udata == nullptr) { + return false; // 数据处理失败 + } + + // 2. 检查最小长度(6字节头部) + constexpr size_t MIN_HEADER_SIZE = 6; + if (data_size < MIN_HEADER_SIZE) { + return false; // 头部长度不足 + } + + // 3. 提取报文长度(大端序) + nMsgLen = (static_cast(udata[4]) << 8) | udata[5]; + + // 4. 验证完整报文长度 (8 + nMsgLen) + if (data_size < 8 + nMsgLen) { + return false; // 报文不完整 + } + + // 5. 计算数据区长度 删除了功能码和帧序号4字节 + nRecvDataLen = nMsgLen - 4; + + // 6. CRC校验(根据实际需要实现) + /* + if (!ValidateCRC(udata, 8 + nMsgLen)) { + return false; // CRC校验失败 + } + */ + + // 7. 提取消息类型 (索引位置 6 + 2 = 8) + msgType = udata[8]; + + // 8. 提取数据区 (索引位置12开始) + RecvData.clear(); + if (nRecvDataLen > 0) { + // 确保不越界(nRecvDataLen = nMsgLen - 4) + RecvData.assign(udata + 12, udata + 12 + nRecvDataLen); + } + + return true; // 数据处理成功 + } +}; + +//接收装置时标对象 +class tagTime { +public: + uint16_t DeviceYear; + uint16_t DeviceMonth; + uint16_t DeviceDay; + uint16_t DeviceHour; + uint16_t DeviceMinute; + uint16_t DeviceSecond; + + // 返回结构体二进制大小 + static constexpr size_t GetSize() { + return 6 * sizeof(uint16_t); + } + + // 默认构造函数 + tagTime() : + DeviceYear(1970), + DeviceMonth(1), + DeviceDay(1), + DeviceHour(0), + DeviceMinute(0), + DeviceSecond(0) {} + + // 从std::tm构造 + explicit tagTime(const std::tm& dt) : + DeviceYear(static_cast(dt.tm_year + 1900)), + DeviceMonth(static_cast(dt.tm_mon + 1)), + DeviceDay(static_cast(dt.tm_mday)), + DeviceHour(static_cast(dt.tm_hour)), + DeviceMinute(static_cast(dt.tm_min)), + DeviceSecond(static_cast(dt.tm_sec)) {} + + // 复制函数 + void Clone(const tagTime& src) { + DeviceYear = src.DeviceYear; + DeviceMonth = src.DeviceMonth; + DeviceDay = src.DeviceDay; + DeviceHour = src.DeviceHour; + DeviceMinute = src.DeviceMinute; + DeviceSecond = src.DeviceSecond; + } + + // 从二进制流解析(网络字节序) + bool SetStructBuf(const uint8_t* bArray, size_t bufSize, size_t offset = 0) { + if (bufSize - offset < GetSize()) { + return false; + } + + const uint8_t* ptr = bArray + offset; + + DeviceYear = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(uint16_t); + DeviceMonth = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(uint16_t); + DeviceDay = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(uint16_t); + DeviceHour = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(uint16_t); + DeviceMinute = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(uint16_t); + DeviceSecond = ntohs(*reinterpret_cast(ptr)); + + return true; + } + + // 序列化为二进制流(网络字节序) + size_t GetStructBuf(uint8_t* bArray, size_t bufSize, size_t offset = 0) const { + if (bufSize - offset < GetSize()) { + return 0; + } + + uint8_t* ptr = bArray + offset; + + *reinterpret_cast(ptr) = htons(DeviceYear); + ptr += sizeof(uint16_t); + *reinterpret_cast(ptr) = htons(DeviceMonth); + ptr += sizeof(uint16_t); + *reinterpret_cast(ptr) = htons(DeviceDay); + ptr += sizeof(uint16_t); + *reinterpret_cast(ptr) = htons(DeviceHour); + ptr += sizeof(uint16_t); + *reinterpret_cast(ptr) = htons(DeviceMinute); + ptr += sizeof(uint16_t); + *reinterpret_cast(ptr) = htons(DeviceSecond); + + return GetSize(); + } +}; + +//谐波间谐波序列长度 默认50 +constexpr int HARMNUM = 50; + +// 间谐波数据结构 +struct tagInHarmData { + int32_t Val; + int32_t f; + + static constexpr size_t GetSize() { + return sizeof(Val) + sizeof(f); + } + + // 从网络字节序解析 + bool SetStructBuf(const uint8_t* ptr) { + Val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + f = ntohl(*reinterpret_cast(ptr)); + return true; + } +}; + +// 功率数据结构 +struct tagPowerData { + int32_t P; + int32_t Q; + int32_t S; + + static constexpr size_t GetSize() { + return sizeof(P) + sizeof(Q) + sizeof(S); + } + + // 从网络字节序解析 + bool SetStructBuf(const uint8_t* ptr) { + P = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + Q = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + S = ntohl(*reinterpret_cast(ptr)); + return true; + } +}; + +// 主数据结构 (使用1字节对齐) +#pragma pack(push, 1) +class tagPqData { +public: + int16_t name; // 监测点号 + int16_t Data_Type; // 数据类型 + tagTime time; // 时间 + + // 各种数据数组 + std::array Rms; // 电压/电流有效值 + std::array UU_Deviation; // 电压上偏差 + std::array UL_Deviation; // 电压下偏差 + std::array F_Deviation; // 频率偏差 + std::array, 2> UI_Seq; // 电压电流序量 + std::array, 6> FuHarm; // 整次谐波 + std::array, 6> FuHarmPhase; // 谐波相角 + std::array, 6> InHarm; // 间谐波 + std::array, 4> Total_Power; // 总功率 + std::array, 4> Harm_Power; // 谐波功率 + std::array, 6> Harm_Contain; // 谐波含有率 + std::array Harm_Aberrance; // 谐波畸变率 + std::array Cos_PF; // 视在功率因数 + std::array Cos_DF; // 位移功率因数 + std::array U_Fluctuation; // 电压波动 + std::array U_Flicker; // 电压闪变 + std::array UL_Flicker; // 电压长闪变 + + // 构造函数 + tagPqData() : name(0), Data_Type(0) { + // 所有数组初始化为0 + Rms.fill(0); + UU_Deviation.fill(0); + UL_Deviation.fill(0); + F_Deviation.fill(0); + + for (auto& arr : UI_Seq) arr.fill(0); + for (auto& arr : FuHarm) arr.fill(0); + for (auto& arr : FuHarmPhase) arr.fill(0); + for (auto& arr : Harm_Contain) arr.fill(0); + + Harm_Aberrance.fill(0); + Cos_PF.fill(0); + Cos_DF.fill(0); + U_Fluctuation.fill(0); + U_Flicker.fill(0); + UL_Flicker.fill(0); + } + + // 获取结构体大小 + static constexpr size_t GetSize() { + return sizeof(name) + sizeof(Data_Type) + + tagTime::GetSize() + + sizeof(Rms) + + sizeof(UU_Deviation) + + sizeof(UL_Deviation) + + sizeof(F_Deviation) + + sizeof(UI_Seq) + + sizeof(FuHarm) + + sizeof(FuHarmPhase) + + sizeof(InHarm) + + sizeof(Total_Power) + + sizeof(Harm_Power) + + sizeof(Harm_Contain) + + sizeof(Harm_Aberrance) + + sizeof(Cos_PF) + + sizeof(Cos_DF) + + sizeof(U_Fluctuation) + + sizeof(U_Flicker) + + sizeof(UL_Flicker); + } + + // 从网络字节序解析二进制数据 + bool SetStructBuf(const uint8_t* bArray, size_t bufSize, size_t offset = 0) { + if (bufSize - offset < GetSize()) { + return false; + } + + const uint8_t* ptr = bArray + offset; + size_t remaining = bufSize - offset; + + // 解析基本字段 + name = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(name); + remaining -= sizeof(name); + + Data_Type = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(Data_Type); + remaining -= sizeof(Data_Type); + + // 解析时间结构 + if (!time.SetStructBuf(ptr, remaining)) { + return false; + } + ptr += tagTime::GetSize(); + remaining -= tagTime::GetSize(); + + // 解析一维int32数组 - 使用显式循环 + for (auto& val : Rms) { + if (remaining < sizeof(int32_t)) return false; + val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + remaining -= sizeof(int32_t); + } + + for (auto& val : UU_Deviation) { + if (remaining < sizeof(int32_t)) return false; + val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + remaining -= sizeof(int32_t); + } + + for (auto& val : UL_Deviation) { + if (remaining < sizeof(int32_t)) return false; + val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + remaining -= sizeof(int32_t); + } + + for (auto& val : F_Deviation) { + if (remaining < sizeof(int32_t)) return false; + val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + remaining -= sizeof(int32_t); + } + + // 解析二维int32数组 - 使用显式循环 + for (auto& arr : UI_Seq) { + for (auto& val : arr) { + if (remaining < sizeof(int32_t)) return false; + val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + remaining -= sizeof(int32_t); + } + } + + for (auto& arr : FuHarm) { + for (auto& val : arr) { + if (remaining < sizeof(int32_t)) return false; + val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + remaining -= sizeof(int32_t); + } + } + + for (auto& arr : FuHarmPhase) { + for (auto& val : arr) { + if (remaining < sizeof(int32_t)) return false; + val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + remaining -= sizeof(int32_t); + } + } + + // 解析间谐波数据 + for (auto& arr : InHarm) { + for (auto& item : arr) { + if (remaining < tagInHarmData::GetSize()) return false; + item.SetStructBuf(ptr); + ptr += tagInHarmData::GetSize(); + remaining -= tagInHarmData::GetSize(); + } + } + + // 解析总功率 + for (auto& arr : Total_Power) { + for (auto& val : arr) { + if (remaining < sizeof(int32_t)) return false; + val = ntohl(*reinterpret_cast(ptr)); + ptr += sizeof(int32_t); + remaining -= sizeof(int32_t); + } + } + + // 解析谐波功率数据 + for (auto& arr : Harm_Power) { + for (auto& item : arr) { + if (remaining < tagPowerData::GetSize()) return false; + item.SetStructBuf(ptr); + ptr += tagPowerData::GetSize(); + remaining -= tagPowerData::GetSize(); + } + } + + // 解析二维int16数组 - 使用显式循环 + for (auto& arr : Harm_Contain) { + for (auto& val : arr) { + if (remaining < sizeof(int16_t)) return false; + val = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(int16_t); + remaining -= sizeof(int16_t); + } + } + + // 解析一维int16数组 - 使用显式循环 + for (auto& val : Harm_Aberrance) { + if (remaining < sizeof(int16_t)) return false; + val = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(int16_t); + remaining -= sizeof(int16_t); + } + + for (auto& val : Cos_PF) { + if (remaining < sizeof(int16_t)) return false; + val = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(int16_t); + remaining -= sizeof(int16_t); + } + + for (auto& val : Cos_DF) { + if (remaining < sizeof(int16_t)) return false; + val = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(int16_t); + remaining -= sizeof(int16_t); + } + + for (auto& val : U_Fluctuation) { + if (remaining < sizeof(int16_t)) return false; + val = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(int16_t); + remaining -= sizeof(int16_t); + } + + for (auto& val : U_Flicker) { + if (remaining < sizeof(int16_t)) return false; + val = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(int16_t); + remaining -= sizeof(int16_t); + } + + for (auto& val : UL_Flicker) { + if (remaining < sizeof(int16_t)) return false; + val = ntohs(*reinterpret_cast(ptr)); + ptr += sizeof(int16_t); + remaining -= sizeof(int16_t); + } + + return true; + } +}; +#pragma pack(pop) + +// 间谐波浮点结构 +struct tagInHarmData_float { + float Val; + float f; +}; + +// 功率浮点结构 +struct tagPowerData_float { + float P; + float Q; + float S; +}; + +// PQ数据浮点结构 +class tagPqData_Float { +public: + short name; // 监测点号 + short Data_Type; // 数据类型 + tagTime time; // 时间 + + // 各种浮点数组 + std::array Rms; + std::array UU_Deviation; + std::array UL_Deviation; + std::array F_Deviation; + std::array, 2> UI_Seq; + std::array, 6> FuHarm; + std::array, 6> FuHarmPhase; + std::array, 6> InHarm; + std::array, 4> Total_Power; + std::array, 4> Harm_Power; + std::array, 6> Harm_Contain; + std::array Harm_Aberrance; + std::array Cos_PF; + std::array Cos_DF; + std::array U_Fluctuation; + std::array U_Flicker; + std::array UL_Flicker; + + // 构造函数初始化数组 + tagPqData_Float() { + Rms.fill(0.0f); + UU_Deviation.fill(0.0f); + UL_Deviation.fill(0.0f); + F_Deviation.fill(0.0f); + + for (auto& arr : UI_Seq) arr.fill(0.0f); + for (auto& arr : FuHarm) arr.fill(0.0f); + for (auto& arr : FuHarmPhase) arr.fill(0.0f); + for (auto& arr : Harm_Contain) arr.fill(0.0f); + + Harm_Aberrance.fill(0.0f); + Cos_PF.fill(0.0f); + Cos_DF.fill(0.0f); + U_Fluctuation.fill(0.0f); + U_Flicker.fill(0.0f); + UL_Flicker.fill(0.0f); + + // 初始化嵌套结构 + for (auto& arr : InHarm) { + for (auto& item : arr) { + item = tagInHarmData_float{ 0.0f, 0.0f }; + } + } + + for (auto& arr : Harm_Power) { + for (auto& item : arr) { + item = tagPowerData_float{ 0.0f, 0.0f, 0.0f }; + } + } + } + + // 转换函数 + void SetFloatValue(const tagPqData& SrcData, float fPT, float fCT) { + time.Clone(SrcData.time); + + // F_Deviation + for (int i = 0; i < 2; i++) { + F_Deviation[i] = IntToFloat(SrcData.F_Deviation[i]); + } + + // UI_Seq + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 4; j++) { + if (i == 0) { // 电压 + if (j == 2) { // 正序 + UI_Seq[i][j] = IntToFloat(SrcData.UI_Seq[i][j]);// *fPT; + } + else if (j < 3) { + UI_Seq[i][j] = IntToFloat(SrcData.UI_Seq[i][j]);// *fPT; + } + else { + UI_Seq[i][j] = IntToFloat(SrcData.UI_Seq[i][j]); + } + } + else { // 电流 + if (j < 3) { + UI_Seq[i][j] = IntToFloat(SrcData.UI_Seq[i][j]);// *fCT; + } + else { + UI_Seq[i][j] = IntToFloat(SrcData.UI_Seq[i][j]); + } + } + } + } + + // 波动和闪变 + for (int i = 0; i < 3; i++) { + U_Fluctuation[i] = ShorToFloat1000(SrcData.U_Fluctuation[i]); + U_Flicker[i] = ShorToFloat1000(SrcData.U_Flicker[i]); + UL_Flicker[i] = ShorToFloat1000(SrcData.UL_Flicker[i]); + } + + // 功率因数 + for (int i = 0; i < 4; i++) { + Cos_PF[i] = ShorToFloat10000(SrcData.Cos_PF[i]); + Cos_DF[i] = ShorToFloat10000(SrcData.Cos_DF[i]); + } + + // 总功率 + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 3; j++) { + Total_Power[i][j] = IntToFloat(SrcData.Total_Power[i][j]);// *fPT* fCT; + } + } + + // 谐波功率 + for (int i = 0; i < 4; i++) { + for (int j = 0; j < HARMNUM; j++) { + Harm_Power[i][j].P = IntToFloat(SrcData.Harm_Power[i][j].P);// * fPT * fCT; + Harm_Power[i][j].Q = IntToFloat(SrcData.Harm_Power[i][j].Q);// *fPT* fCT; + Harm_Power[i][j].S = IntToFloat(SrcData.Harm_Power[i][j].S);// *fPT* fCT; + } + } + + // 谐波相关数据 + for (int i = 0; i < 6; i++) { + UU_Deviation[i] = IntToFloat(SrcData.UU_Deviation[i]); + UL_Deviation[i] = IntToFloat(SrcData.UL_Deviation[i]); + Harm_Aberrance[i] = ShorToFloat100(SrcData.Harm_Aberrance[i]); + + for (int j = 0; j < HARMNUM; j++) { + if (i < 3) { // 电压谐波 + FuHarm[i][j] = IntToFloat(SrcData.FuHarm[i][j]);// *fPT; + } + else { // 电流谐波 + FuHarm[i][j] = IntToFloat(SrcData.FuHarm[i][j]);// *fCT; + } + + FuHarmPhase[i][j] = IntToFloat(SrcData.FuHarmPhase[i][j]); + InHarm[i][j].Val = IntToFloat(SrcData.InHarm[i][j].Val); + Harm_Contain[i][j] = ShorToFloat100(SrcData.Harm_Contain[i][j]); + } + } + + // RMS值 + for (int i = 0; i < 9; i++) { + if (i > 2 && i < 6) { // 电流 (索引3,4,5) + Rms[i] = IntToFloat(SrcData.Rms[i]);// *fCT; + } + else { // 电压和其他 + Rms[i] = IntToFloat(SrcData.Rms[i]);// *fPT; + } + } + } + + // 将浮点字段转换为Base64字符串 + std::string ConvertToBase64() const { + // 1. 计算总浮点数 + const size_t total_floats = CalculateFloatCount(); + + // 2. 创建缓冲区并填充数据 + std::vector float_buffer; + float_buffer.reserve(total_floats); + SerializeFloats(float_buffer); + + // 3. 将浮点缓冲区转换为字节数据 + const size_t byte_size = float_buffer.size() * sizeof(float); + const unsigned char* byte_data = + reinterpret_cast(float_buffer.data()); + + // 4. Base64编码 + return base64_encode(byte_data, byte_size); + } + + // 计算浮点字段总数 + size_t CalculateFloatCount() const { + size_t count = 0; + + // 基本数组 + count += Rms.size(); + count += UU_Deviation.size(); + count += UL_Deviation.size(); + count += F_Deviation.size(); + + // 二维数组 + for (const auto& arr : UI_Seq) count += arr.size(); + for (const auto& arr : FuHarm) count += arr.size(); + for (const auto& arr : FuHarmPhase) count += arr.size(); + + // 嵌套结构数组 + for (const auto& arr : InHarm) { + for (const auto& item : arr) { + count += 2; // 每个tagInHarmData_float包含2个float + } + } + + // 功率数组 + for (const auto& arr : Total_Power) count += arr.size(); + + for (const auto& arr : Harm_Power) { + for (const auto& item : arr) { + count += 3; // 每个tagPowerData_float包含3个float + } + } + + // 其他数组 + for (const auto& arr : Harm_Contain) count += arr.size(); + count += Harm_Aberrance.size(); + count += Cos_PF.size(); + count += Cos_DF.size(); + count += U_Fluctuation.size(); + count += U_Flicker.size(); + count += UL_Flicker.size(); + + 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.14159f); + } + + // 12-14位从UU_Deviation和UL_Deviation各自取前三个,取不为0的值 + for (int i = 0; i < 3; ++i) { + // 直接选择绝对值更大的那个(必然是有效数值) + float val = (fabs(UU_Deviation[i]) > fabs(UL_Deviation[i])) + ? 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.14159f); + } + + // 再后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.14159f); + } + + // 再后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.14159f); + } + + // 再后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.14159f); + } + + // 再后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.14159f); + } + + // 再后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.14159f); + } + + // 再后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.14159f); + } + + // 再后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.14159f); + } + + // 再后3位从UL_Flicker中取0-2 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(UL_Flicker[i]); + } + + //后12位 A相P1 Q1 S1 B相P1 Q1 S1 C相P1 Q1 S1 T相P1 Q1 S1 + float_buffer.push_back(Harm_Power[0][0].P); + float_buffer.push_back(Harm_Power[0][0].Q); + float_buffer.push_back(Harm_Power[0][0].S); + float_buffer.push_back(Harm_Power[1][0].P); + float_buffer.push_back(Harm_Power[1][0].Q); + float_buffer.push_back(Harm_Power[1][0].S); + float_buffer.push_back(Harm_Power[2][0].P); + float_buffer.push_back(Harm_Power[2][0].Q); + float_buffer.push_back(Harm_Power[2][0].S); + float_buffer.push_back(Harm_Power[3][0].P); + float_buffer.push_back(Harm_Power[3][0].Q); + float_buffer.push_back(Harm_Power[3][0].S); + //后9位 相电压 相电流 线电压 (基波有效值 A B C V1 I1)FuHarm取数组0位 + float_buffer.push_back(3.14159f);//A V1 角型空置 + float_buffer.push_back(3.14159f);//B V1 角型空置 + float_buffer.push_back(3.14159f);//C V1 角型空置 + float_buffer.push_back(FuHarm[3][0]);//A I1 + float_buffer.push_back(FuHarm[4][0]);//B I1 + float_buffer.push_back(FuHarm[5][0]);//C I1 + float_buffer.push_back(FuHarm[0][0]);//AB V1 + float_buffer.push_back(FuHarm[1][0]);//BC V1 + float_buffer.push_back(FuHarm[2][0]);//CA V1 + //后9位 基波电压电流相角 FuHarmPhase取数组0位 + float_buffer.push_back(3.14159f);//A V1 角型空置 + float_buffer.push_back(3.14159f);//B V1 角型空置 + float_buffer.push_back(3.14159f);//C V1 角型空置 + float_buffer.push_back(FuHarmPhase[3][0]);//A I1 + float_buffer.push_back(FuHarmPhase[4][0]);//B I1 + float_buffer.push_back(FuHarmPhase[5][0]);//C I1 + float_buffer.push_back(FuHarmPhase[0][0]);//AB V1 + float_buffer.push_back(FuHarmPhase[1][0]);//BC V1 + float_buffer.push_back(FuHarmPhase[2][0]);//CA V1 + + // 转换为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 //电压有效值//电流有效值//线电压有效值 以上九个为原结构rms + 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 = (fabs(UU_Deviation[i]) > fabs(UL_Deviation[i])) + ? UU_Deviation[i] + : -UL_Deviation[i]; + float_buffer.push_back(val); + } + + // 12-14位置位3.1415表示空置 //线电压偏差 原UU_Deviation和UL_Deviation结构上下偏差需要判断并转换 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.14159f); + } + + // 15-16位从F_Deviation中取0-1 //频率偏差+频率 原F_Deviation结构 + for (int i = 0; i < 2; ++i) { + float_buffer.push_back(F_Deviation[i]); + } + + // 再后8位从UI_Seq取0-7 //电压零负正分量和负序不平衡//电流零负正分量和负序不平衡 原UI_Seq结构 + 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开始)//相电压谐波有效值A B C FuHarm 0-2 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位 //相电流谐波有效值A B C FuHarm 3-5 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表示空置 //线电压谐波有效值 AB BC CA FuHarm 0-2 1-49 云前置新增指标 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.14159f); + } + + // 再后49*3位依次从FuHarmPhase的0-2中取1-49位 //相电压谐波相角 A B C 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位 //相电流谐波相角 A B C 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表示空置 //线电压谐波相角 AB BC CA FuHarmPhase 0-2 1-49 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.14159f); + } + + // 再后50*6位依次从InHarm的0-5中取0-49位中的val指标 //相电压间谐波有效值A B C InHarm 0-2 0-49 云前置新增指标//相电流间谐波有效值A B C InHarm 3-5 0-49 + 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表示空置 //线电压间谐波有效值AB BC CA InHarm 0-2 0-49 云前置新增指标 + for (int i = 0; i < 50 * 3; ++i) { + float_buffer.push_back(3.14159f); + } + + // 再后12位依次从Total_Power的0-3中取0-2位 //A相 有功 无功 视在 Total_Power 0 0-2 B相 有功 无功 视在 Total_Power 1 0-2 C相 有功 无功 视在 Total_Power 2 0-2 T相 有功 无功 视在 Total_Power 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值 //A相 有功 无功 视在 Harm_Power 0 1-49 0-2 + 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值 //B相 有功 无功 视在 Harm_Power 1 1-49 0-2 + 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值 //C相 有功 无功 视在 Harm_Power 2 1-49 0-2 + 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值 //三相总 有功 无功 视在 Harm_Power 3 1-49 0-2 + 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位 //相电压谐波含有率A B C Harm_Contain 0-2 1-49 //相电流谐波含有率A B C Harm_Contain 3-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表示空置 //线电压谐波含有率AB BC CA Harm_Contain 0-2 1-49 + for (int i = 0; i < 49 * 3; ++i) { + float_buffer.push_back(3.14159f); + } + + // 再后6位从Harm_Aberrance中的0-5中取值 //相电压谐波总畸变率A B C Harm_Aberrance 0-2 //相电流谐波总畸变率A B C Harm_Aberrance 3-5 + for (int i = 0; i < 6; ++i) { + float_buffer.push_back(Harm_Aberrance[i]); + } + // 再后3位置位3.1415表示空置 //线电压谐波总畸变率AB BC CA Harm_Aberrance 0-2 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.14159f); + } + + // 再后4位从Cos_PF中取0-3 //三相功率因数和总功率因数 Cos_PF 0-3 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(Cos_PF[i]); + } + // 再后4位从Cos_DF中取0-3 //三相基波功率因数和总基波功率因数 Cos_DF 0-3 + for (int i = 0; i < 4; ++i) { + float_buffer.push_back(Cos_DF[i]); + } + + // 再后3位从U_Fluctuation中取0-2 //三相电压变动幅值 U_Fluctuation + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(U_Fluctuation[i]); + } + // 再后3位置位3.1415表示空置 //三线电压变动幅值 U_Fluctuation + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.14159f); + } + + // 再后3位从U_Flicker中取0-2 //三相电压短闪U_Flicker + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(U_Flicker[i]); + } + // 再后3位置位3.1415表示空置 //三线电压短闪U_Flicker + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.14159f); + } + + // 再后3位从UL_Flicker中取0-2 //三相电压长闪UL_Flicker + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(UL_Flicker[i]); + } + // 再后3位置位3.1415表示空置 //三线电压长闪UL_Flicker + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(3.14159f); + } + + //后12位 A相P1 Q1 S1 B相P1 Q1 S1 C相P1 Q1 S1 T相P1 Q1 S1 + float_buffer.push_back(Harm_Power[0][0].P); //A相 P1 Q1 S1 Harm_Power取数组0位 + float_buffer.push_back(Harm_Power[0][0].Q); + float_buffer.push_back(Harm_Power[0][0].S); + float_buffer.push_back(Harm_Power[1][0].P); //B相 P1 Q1 S1 + float_buffer.push_back(Harm_Power[1][0].Q); + float_buffer.push_back(Harm_Power[1][0].S); + float_buffer.push_back(Harm_Power[2][0].P); //C相 P1 Q1 S1 + float_buffer.push_back(Harm_Power[2][0].Q); + float_buffer.push_back(Harm_Power[2][0].S); + float_buffer.push_back(Harm_Power[3][0].P); //T相 P1 Q1 S1 + float_buffer.push_back(Harm_Power[3][0].Q); + float_buffer.push_back(Harm_Power[3][0].S); + //后9位 相电压 相电流 线电压 (基波有效值 A B C V1 I1)FuHarm取数组0位 + float_buffer.push_back(FuHarm[0][0]);//A V1 //相电压-基波电压有效值A B C V1 FuHarm取数组0位 + float_buffer.push_back(FuHarm[1][0]);//B V1 + float_buffer.push_back(FuHarm[2][0]);//C V1 + float_buffer.push_back(FuHarm[3][0]);//A I1 //相电流-基波电流有效值A B C I1 + float_buffer.push_back(FuHarm[4][0]);//B I1 + float_buffer.push_back(FuHarm[5][0]);//C I1 + float_buffer.push_back(3.14159f);//AB V1 星型空置 //线电压-基波电压有效值A B C V1 + float_buffer.push_back(3.14159f);//BC V1 星型空置 + float_buffer.push_back(3.14159f);//CA V1 星型空置 + //后9位 基波电压电流相角 FuHarmPhase取数组0位 + float_buffer.push_back(FuHarmPhase[0][0]);//A V1 //相电压-基波电压相角A B C V1 FuHarmPhase取数组0位 + float_buffer.push_back(FuHarmPhase[1][0]);//B V1 + float_buffer.push_back(FuHarmPhase[2][0]);//C V1 + float_buffer.push_back(FuHarmPhase[3][0]);//A I1 //相电流-基波电流相角A B C I1 FuHarmPhase取数组0位 + float_buffer.push_back(FuHarmPhase[4][0]);//B I1 + float_buffer.push_back(FuHarmPhase[5][0]);//C I1 + float_buffer.push_back(3.14159f);//AB V1 星型空置 //线电压-基波电压相角A B C V1 + float_buffer.push_back(3.14159f);//BC V1 星型空置 + float_buffer.push_back(3.14159f);//CA V1 星型空置 + + // 转换为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 { + // 基本数组 + for (const auto& val : Rms) buffer.push_back(val); + for (const auto& val : UU_Deviation) buffer.push_back(val); + for (const auto& val : UL_Deviation) buffer.push_back(val); + for (const auto& val : F_Deviation) buffer.push_back(val); + + // 二维数组 + for (const auto& arr : UI_Seq) { + for (const auto& val : arr) buffer.push_back(val); + } + for (const auto& arr : FuHarm) { + for (const auto& val : arr) buffer.push_back(val); + } + for (const auto& arr : FuHarmPhase) { + for (const auto& val : arr) buffer.push_back(val); + } + + // 嵌套结构数组 + for (const auto& arr : InHarm) { + for (const auto& item : arr) { + buffer.push_back(item.Val); + buffer.push_back(item.f); + } + } + + // 功率数组 + for (const auto& arr : Total_Power) { + for (const auto& val : arr) buffer.push_back(val); + } + + for (const auto& arr : Harm_Power) { + for (const auto& item : arr) { + buffer.push_back(item.P); + buffer.push_back(item.Q); + buffer.push_back(item.S); + } + } + + // 其他数组 + for (const auto& arr : Harm_Contain) { + for (const auto& val : arr) buffer.push_back(val); + } + for (const auto& val : Harm_Aberrance) buffer.push_back(val); + for (const auto& val : Cos_PF) buffer.push_back(val); + for (const auto& val : Cos_DF) buffer.push_back(val); + for (const auto& val : U_Fluctuation) buffer.push_back(val); + for (const auto& val : U_Flicker) buffer.push_back(val); + for (const auto& val : UL_Flicker) buffer.push_back(val); + } + + // Base64编码函数 + static std::string base64_encode(const unsigned char* bytes_to_encode, size_t in_len) { + static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; i < 4; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; j < i + 1; j++) + ret += base64_chars[char_array_4[j]]; + + while (i++ < 3) + ret += '='; + } + + return ret; + } +}; + +//计算报文帧长度 1帧1024为1K 统计数据相关 +constexpr int PqDataLen = tagPqData::GetSize(); +constexpr int Stat_PacketNum = (PqDataLen / 1024 > 0) ? (PqDataLen / 1024 + 1) : (PqDataLen / 1024); + +//实时数据结构(1字节对齐) +#pragma pack(push, 1) +class RealtagPqDate_float { +public: + tagTime time; // 时间 + + //实时数据各浮点数组 + std::array Rms; //相电压、线电压、电流有效值 + std::array UU_Deviation; //相电压、线电压上偏差 + std::array UL_Deviation; //相电压、线电压下偏差 + std::array THD; //电压电流畸变率 + std::array FREQ; //频率及频率偏差 + std::array, 2> UI_Seq;//电压电流序分量及不平衡度 + std::array, 4> TOTAL_POWER;//分相及总功率P、Q、S + std::array COS_PF; //视在功率因数 + std::array COS_DF; //位移功率因数 + //----------- 报文一包含时间和以上数据 + + std::array, 3> HARMV;//谐波电压含有率 + //----------- 报文二包含时间和以上数据 + + std::array, 3> HARMI;//谐波电流幅值 + //----------- 报文三包含时间和以上数据 + + std::array, 3> HARMVP;//谐波电压相位 + //----------- 报文四包含时间和以上数据 + + std::array, 3> HARMIP;//谐波电流相位 + //----------- 报文五包含时间和以上数据 + + std::array, 3> INHARMV;//间谐波电压幅值 + //----------- 报文六包含时间和以上数据 + + // 构造函数 - 初始化所有数据 + RealtagPqDate_float() { + // 初始化时间 + time = tagTime(); // 调用tagTime的默认构造函数 + + // 初始化基本数组 + Rms.fill(0.0f); + UU_Deviation.fill(0.0f); + UL_Deviation.fill(0.0f); + THD.fill(0.0f); + FREQ.fill(0.0f); + COS_PF.fill(0.0f); + COS_DF.fill(0.0f); + + // 初始化二维数组 + for (auto& arr : UI_Seq) { + arr.fill(0.0f); + } + for (auto& arr : TOTAL_POWER) { + arr.fill(0.0f); + } + + // 初始化谐波相关数组 + for (auto& arr : HARMV) { + arr.fill(0.0f); + } + for (auto& arr : HARMI) { + arr.fill(0.0f); + } + for (auto& arr : HARMVP) { + arr.fill(0.0f); + } + for (auto& arr : HARMIP) { + arr.fill(0.0f); + } + for (auto& arr : INHARMV) { + arr.fill(0.0f); + } + } + + // 辅助函数:从网络字节序读取float + float read_net_float(const uint8_t* ptr) { + uint32_t temp; + memcpy(&temp, ptr, sizeof(uint32_t)); + temp = ntohl(temp); + float result; + memcpy(&result, &temp, sizeof(float)); + return result; + } + + // 实时数据结构的分包解析方法 + bool ParsePacket1(const uint8_t* data, size_t size) { + // 最小长度 = 时间(12字节) + 后续数据(59个float * 4 = 236字节) = 248字节 + const size_t min_size = tagTime::GetSize() + 59 * sizeof(float); + if (size < min_size) { + return false; + } + + // 解析时间 + if (!time.SetStructBuf(data, size)) { + return false; + } + const uint8_t* ptr = data + tagTime::GetSize(); + + // 解析Rms (9个float) + for (int i = 0; i < 9; ++i) { + Rms[i] = read_net_float(ptr); + ptr += sizeof(float); + } + + // 解析UU_Deviation (6个float) + for (int i = 0; i < 6; ++i) { + UU_Deviation[i] = read_net_float(ptr); + ptr += sizeof(float); + } + + // 解析UL_Deviation (6个float) + for (int i = 0; i < 6; ++i) { + UL_Deviation[i] = read_net_float(ptr); + ptr += sizeof(float); + } + + // 解析THD (6个float) + for (int i = 0; i < 6; ++i) { + THD[i] = read_net_float(ptr); + ptr += sizeof(float); + } + + // 解析FREQ (2个float) + for (int i = 0; i < 2; ++i) { + FREQ[i] = read_net_float(ptr); + ptr += sizeof(float); + } + + // 解析UI_Seq (2x5个float) + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 5; ++j) { + UI_Seq[i][j] = read_net_float(ptr); + ptr += sizeof(float); + } + } + + // 解析TOTAL_POWER (4x3个float) + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 3; ++j) { + TOTAL_POWER[i][j] = read_net_float(ptr); + ptr += sizeof(float); + } + } + + // 解析COS_PF (4个float) + for (int i = 0; i < 4; ++i) { + COS_PF[i] = read_net_float(ptr); + ptr += sizeof(float); + } + + // 解析COS_DF (4个float) + for (int i = 0; i < 4; ++i) { + COS_DF[i] = read_net_float(ptr); + ptr += sizeof(float); + } + + return true; + } + + bool ParsePacket2(const uint8_t* data, size_t size) { + // 最小长度 = 时间(12字节) + 谐波电压(150个float * 4 = 600字节) = 612字节 + const size_t min_size = tagTime::GetSize() + 3 * HARMNUM * sizeof(float); + if (size < min_size) { + return false; + } + + // 解析时间(覆盖之前的时间) + if (!time.SetStructBuf(data, size)) { + return false; + } + const uint8_t* ptr = data + tagTime::GetSize(); + + // 解析HARMV (3xHARMNUM个float) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < HARMNUM; ++j) { + HARMV[i][j] = read_net_float(ptr); + ptr += sizeof(float); + } + } + + return true; + } + + bool ParsePacket3(const uint8_t* data, size_t size) { + // 最小长度 = 时间(12字节) + 谐波电流(150个float * 4 = 600字节) = 612字节 + const size_t min_size = tagTime::GetSize() + 3 * HARMNUM * sizeof(float); + if (size < min_size) { + return false; + } + + if (!time.SetStructBuf(data, size)) { + return false; + } + const uint8_t* ptr = data + tagTime::GetSize(); + + // 解析HARMI (3xHARMNUM个float) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < HARMNUM; ++j) { + HARMI[i][j] = read_net_float(ptr); + ptr += sizeof(float); + } + } + + return true; + } + + bool ParsePacket4(const uint8_t* data, size_t size) { + // 最小长度 = 时间(12字节) + 谐波电压相位(150个float * 4 = 600字节) = 612字节 + const size_t min_size = tagTime::GetSize() + 3 * HARMNUM * sizeof(float); + if (size < min_size) { + return false; + } + + if (!time.SetStructBuf(data, size)) { + return false; + } + const uint8_t* ptr = data + tagTime::GetSize(); + + // 解析HARMVP (3xHARMNUM个float) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < HARMNUM; ++j) { + HARMVP[i][j] = read_net_float(ptr); + ptr += sizeof(float); + } + } + + return true; + } + + bool ParsePacket5(const uint8_t* data, size_t size) { + // 最小长度 = 时间(12字节) + 谐波电流相位(150个float * 4 = 600字节) = 612字节 + const size_t min_size = tagTime::GetSize() + 3 * HARMNUM * sizeof(float); + if (size < min_size) { + return false; + } + + if (!time.SetStructBuf(data, size)) { + return false; + } + const uint8_t* ptr = data + tagTime::GetSize(); + + // 解析HARMIP (3xHARMNUM个float) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < HARMNUM; ++j) { + HARMIP[i][j] = read_net_float(ptr); + ptr += sizeof(float); + } + } + + return true; + } + + bool ParsePacket6(const uint8_t* data, size_t size) { + // 最小长度 = 时间(12字节) + 间谐波电压(150个float * 4 = 600字节) = 612字节 + const size_t min_size = tagTime::GetSize() + 3 * HARMNUM * sizeof(float); + if (size < min_size) { + return false; + } + + if (!time.SetStructBuf(data, size)) { + return false; + } + const uint8_t* ptr = data + tagTime::GetSize(); + + // 解析INHARMV (3xHARMNUM个float) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < HARMNUM; ++j) { + INHARMV[i][j] = read_net_float(ptr); + ptr += sizeof(float); + } + } + + return true; + } + + // 计算浮点字段总数 + size_t CalculateFloatCount() const { + size_t count = 0; + + // 基本数组 + count += Rms.size(); + count += UU_Deviation.size(); + count += UL_Deviation.size(); + count += THD.size(); + count += FREQ.size(); + count += COS_PF.size(); + count += COS_DF.size(); + + // 二维数组 + for (const auto& arr : UI_Seq) count += arr.size(); + for (const auto& arr : TOTAL_POWER) count += arr.size(); + for (const auto& arr : HARMV) count += arr.size(); + for (const auto& arr : HARMI) count += arr.size(); + for (const auto& arr : HARMVP) count += arr.size(); + for (const auto& arr : HARMIP) count += arr.size(); + for (const auto& arr : INHARMV) count += arr.size(); + + return count; + } + + // 序列化浮点数据到缓冲区 + void SerializeFloats(std::vector& buffer) const { + // 基本数组 + for (float val : Rms) buffer.push_back(val); + for (float val : UU_Deviation) buffer.push_back(val); + for (float val : UL_Deviation) buffer.push_back(val); + for (float val : THD) buffer.push_back(val); + for (float val : FREQ) buffer.push_back(val); + + // 二维数组(电压电流序) + for (const auto& arr : UI_Seq) { + for (float val : arr) buffer.push_back(val); + } + + // 功率数组 + for (const auto& arr : TOTAL_POWER) { + for (float val : arr) buffer.push_back(val); + } + + // 功率因数 + for (float val : COS_PF) buffer.push_back(val); + for (float val : COS_DF) buffer.push_back(val); + + // 谐波相关数组 + for (const auto& arr : HARMV) { + for (float val : arr) buffer.push_back(val); + } + for (const auto& arr : HARMI) { + for (float val : arr) buffer.push_back(val); + } + for (const auto& arr : HARMVP) { + for (float val : arr) buffer.push_back(val); + } + for (const auto& arr : HARMIP) { + for (float val : arr) buffer.push_back(val); + } + for (const auto& arr : INHARMV) { + for (float val : arr) buffer.push_back(val); + } + } + + // Base64编码函数(与tagPqData_Float相同) + static std::string base64_encode(const unsigned char* bytes_to_encode, size_t in_len) { + static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; i < 4; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; j < i + 1; j++) + ret += base64_chars[char_array_4[j]]; + + while (i++ < 3) + ret += '='; + } + + return ret; + } + + // 新增Base64转换方法 + std::string ConvertToBase64() const { + // 1. 计算总浮点数 + const size_t total_floats = CalculateFloatCount(); + + // 2. 创建缓冲区并填充数据 + std::vector float_buffer; + float_buffer.reserve(total_floats); + SerializeFloats(float_buffer); + + // 3. 转换为字节数据并编码 + 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 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 val = (fabs(UU_Deviation[i]) > fabs(UL_Deviation[i])) + ? 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.14159f); + } + + // 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.14159f); + } + + // 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 (j == 3) { + float_buffer.push_back(UI_Seq[i][j+1]); + } + else { + 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.14159f); + } + + // 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.14159f); + } + + // 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.14159f); + } + + //后9位 相电压 相电流 线电压 (基波有效值 A B C V1 I1)FuHarm取数组0位 + float_buffer.push_back(HARMV[0][0]);//A V1 + float_buffer.push_back(HARMV[1][0]);//B V1 + float_buffer.push_back(HARMV[2][0]);//C V1 + float_buffer.push_back(HARMI[0][0]);//A I1 + float_buffer.push_back(HARMI[1][0]);//B I1 + float_buffer.push_back(HARMI[2][0]);//C I1 + float_buffer.push_back(3.14159f);//AB V1 星型空置 + float_buffer.push_back(3.14159f);//BC V1 星型空置 + float_buffer.push_back(3.14159f);//CA V1 星型空置 + //后9位 基波电压电流相角 FuHarmPhase取数组0位 + float_buffer.push_back(HARMVP[0][0]);//A V1 + float_buffer.push_back(HARMVP[1][0]);//B V1 + float_buffer.push_back(HARMVP[2][0]);//C V1 + float_buffer.push_back(HARMIP[0][0]);//A I1 + float_buffer.push_back(HARMIP[1][0]);//B I1 + float_buffer.push_back(HARMIP[2][0]);//C I1 + float_buffer.push_back(3.14159f);//AB V1 星型空置 + float_buffer.push_back(3.14159f);//BC V1 星型空置 + float_buffer.push_back(3.14159f);//CA V1 星型空置 + + // 转换为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.14159f); + } + + // 12-14: 电压偏差(取不为0的值) + for (int i = 0; i < 3; ++i) { + //float val = (UU_Deviation[i] != 0.0f) ? UU_Deviation[i] : UL_Deviation[i]; + // 直接选择绝对值更大的那个(必然是有效数值) + float val = (fabs(UU_Deviation[i]) > fabs(UL_Deviation[i])) + ? 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.14159f); + } + + // 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 (j == 3) { + float_buffer.push_back(UI_Seq[i][j + 1]); + } + else { + 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.14159f); + } + + // 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.14159f); + } + + // 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.14159f); + } + + // 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]); + } + } + + //后9位 相电压 相电流 线电压 (基波有效值 A B C V1 I1)FuHarm取数组0位 + float_buffer.push_back(3.14159f);//A V1 角型空置 + float_buffer.push_back(3.14159f);//B V1 角型空置 + float_buffer.push_back(3.14159f);//C V1 角型空置 + float_buffer.push_back(HARMI[0][0]);//A I1 + float_buffer.push_back(HARMI[1][0]);//B I1 + float_buffer.push_back(HARMI[2][0]);//C I1 + float_buffer.push_back(HARMV[0][0]);//AB V1 + float_buffer.push_back(HARMV[1][0]);//BC V1 + float_buffer.push_back(HARMV[2][0]);//CA V1 + //后9位 基波电压电流相角 FuHarmPhase取数组0位 + float_buffer.push_back(3.14159f);//A V1 角型空置 + float_buffer.push_back(3.14159f);//B V1 角型空置 + float_buffer.push_back(3.14159f);//C V1 角型空置 + float_buffer.push_back(HARMIP[0][0]);//A I1 + float_buffer.push_back(HARMIP[1][0]);//B I1 + float_buffer.push_back(HARMIP[2][0]);//C I1 + float_buffer.push_back(HARMVP[0][0]);//AB V1 + float_buffer.push_back(HARMVP[1][0]);//BC V1 + float_buffer.push_back(HARMVP[2][0]);//CA V1 + + // 转换为Base64 + return floatVectorToBase64(float_buffer); + } + + // 角型接线转换函数-谐波电压含有率+畸变率 + std::string ConvertToBase64_Delta_RtHarmV() const { + std::vector float_buffer; + + //THD线电压畸变率(3-5) + /*for (int i = 3; i < 6; ++i) { + float_buffer.push_back(THD[i]); + }*/ + //这里线的指标被填入了相中 所以仍然取0-2而不取3-5 + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(THD[i]); + } + + //电压谐波含有率(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMV[i][j]); + } + } + + // 转换为Base64 + return floatVectorToBase64(float_buffer); + } + + // 星型接线转换函数-谐波电压含有率+畸变率 + std::string ConvertToBase64_Star_RtHarmV() const { + std::vector float_buffer; + + //THD相电压畸变率(0-2) + for (int i = 0; i < 3; ++i) { + float_buffer.push_back(THD[i]); + } + + //电压谐波含有率(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMV[i][j]); + } + } + + // 转换为Base64 + return floatVectorToBase64(float_buffer); + } + + // 根据接线方式选择转换方法 数据全集解析 + std::string ConvertToBase64(int wiringType) const { + // 1为角型接线,其他为星型接线 + if (wiringType == 1) { + return ConvertToBase64_Delta(); + } + else { + return ConvertToBase64_Star(); + } + } + + //单独解析-谐波电压含有率+畸变率 + std::string ConvertToBase64_RtHarmV(int wiringType) const { + // 1为角型接线,其他为星型接线 + if (wiringType == 1) { + return ConvertToBase64_Delta_RtHarmV(); + } + else { + return ConvertToBase64_Star_RtHarmV(); + } + } + + //单独解析-谐波电流幅值 + std::string ConvertToBase64_RtHarmI() const { + std::vector float_buffer; + + //电流谐波幅值(1-49次) + for (int i = 0; i < 3; ++i) { + for (int j = 1; j < HARMNUM; ++j) { + float_buffer.push_back(HARMI[i][j]); + } + } + + // 转换为Base64 + return floatVectorToBase64(float_buffer); + } + + //单独解析-间谐波电压含有率 + std::string ConvertToBase64_RtInHarmV() const { + std::vector float_buffer; + + //电压间谐波幅值(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); + } +}; +#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); +//暂态相关结构------------------------------- + +// 定义目录信息结构体 (1字节对齐) +#pragma pack(push, 1) +struct tag_dir_info { + int32_t flag; // 0-目录,1-文件 + char name[64]; // 文件名/目录名 + uint32_t size; // 文件大小 +}; +#pragma pack(pop) + +// 定值描述文件 +struct DZ_TAB_STRUCT { + short LN_Num; // 监测点 + short DZ_Num; // 序号 + char DZ_Name[66]; // 名称 + short DZ_Type; // 定值类型 + float DZ_Min; // 最小值 + float DZ_Max; // 最大值 + float DZ_Default; // 缺省值 + char DZ_UNIT[10]; // 量纲 +}; + +// 控制字描述结构体定义 +#pragma pack(push, 1) // 确保内存紧凑布局 +struct DZ_kzz_bit { + char kzz_bit[40]; // 名称,固定40字节 + char bit_enable; // 是否使用标志(1字节) +}; +#pragma pack(pop) // 恢复默认对齐 + +// 单个内部定值描述结构体 +struct NameFixValue +{ + char uNumber; // 序号 + char sFixValueName[20]; // 名称 (固定20字节) + char uBY; // 备用 + uint16_t DataType; // 数据类型 + uint16_t MinValue; // 最小值 + uint16_t MaxValue; // 最大值 + uint16_t DefaultValue; // 缺省值 + char sDimension[4]; // 单位 (固定4字节) +}; + +// 字节序转换函数 +void ReversalBuff(uint8_t* buff, int start, int length); + +// 生成带协议头的二进制报文 +std::vector generate_binary_message( + uint16_t msg_type, + const std::vector& payload); + +// 生成装置云服务登录报文 +std::vector generate_frontlogin_message(const std::string& strMac); +//生成询问统计数据时间报文 +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); +//生成文件下载请求报文 当前帧序号+文件名 +std::vector generate_downloadfile_message(int frameIndex, const std::string& fileName); +//文件目录读取报文 传入需要读取的文件路径 +std::vector generate_getfilemenu_message(const std::string& filedir); +/** + * @brief 文件上送报文 + * @param data 当前帧上送数据 + * @param sendCount 当前帧序号 + * @param count 总帧数 + * @param fileSize 升级文件总大小 + * @param crc CRC校验值 + * @param filedir 上送全路径 + * @return 包含完整报文的字节向量 + */ +std::vector generate_sendfile_message(const std::vector& data, + std::uint32_t sendCount, + std::uint32_t count, + std::uint32_t fileSize, + std::uint16_t crc, + const std::string& filedir); +/** + * @brief 文件删除报文 + * @param filedir 删除文件全路径 + * @return 包含完整报文的字节向量 + */ +std::vector generate_deletefile_message(const std::string& filedir); +/** + * @brief 文件目录创建报文 + * @param filedir 目录全路径 + * @return 包含完整报文的字节向量 + */ +std::vector generate_setmenu_message(const std::string& filedir); +/** + * @brief 文件目录删除报文 + * @param filedir 目录全路径 + * @return 包含完整报文的字节向量 + */ +std::vector generate_delmenu_message(const std::string& filedir); +// 请求定值报文 传入测点号 +std::vector generate_requestFixValue_message(unsigned char nCpuNo); +// 请求定值描述报文 +std::vector generate_requestFixDes_message(); +// 设置定值报文 传入测点号+修改的定值数据队列 +std::vector generate_requestSetFixValue_message(unsigned char nCpuNo, const std::vector& value); +/** + * @brief 生成请求装置内部定值的报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_requestinterfixvalue_message(); +/** + * @brief 生成请求装置内部定值描述的报文 + * @param nDesCW 描述类型 (1-内部定值描述, 2-控制字描述) + * @return 包含完整报文的字节向量,参数无效时返回空向量 + */ +std::vector generate_requestinterfixdes_message(unsigned char nDesCW); +/** + * @brief 生成设置装置内部定值的报文 + * @param values 要设置的定值数组 (ushort值) + * @return 包含完整报文的字节向量 + */ +std::vector generate_requestsetinterfixvalue_message(const std::vector& values); +std::vector generate_requestsetinterfixvalue_message_new(const std::vector& value); +/** + * @brief 生成装置运行信息读取指令报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_machinestatus_message(); +/** + * @brief 生成装置版本配置信息读取指令报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_machineversion_message(); +/** + * @brief 生成预升级报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_preupgrade_message(); +/** + * @brief 生成正式升级报文-单帧升级文件传输 + * @param data 当前帧升级数据 + * @param updateCount 当前帧序号 + * @param updateSize 升级文件总大小 + * @param count 总帧数 + * @param crc CRC校验值 + * @return 包含完整报文的字节向量 + */ +std::vector generate_upgrade_start_message(const std::vector& data, + std::uint32_t updateCount, + std::uint32_t updateSize, + std::uint32_t count, + std::uint32_t crc); +/** + * @brief 生成正式升级报文-传输完毕开始升级 + * @return 包含完整报文的字节向量 + */ +std::vector generate_upgrade_end_message(); +/** + * @brief 生成设置装置对时的报文 + * @param time 下发的对时时间 (tm值) + * @return 包含完整报文的字节向量 + */ +std::vector generate_righttime_message(const std::tm& time); +/** + * @brief 生成暂降事件补招报文 + * @param Time1 起始时间 + * @param Time2 结束时间 + * @param eventType 事件类型,默认2-暂态事件 4-告警时间 + * @param monitorPoint 监测点,默认1-监测点1 1-6 对应测点 + * @return 包含完整报文的字节向量 + */ +std::vector generate_recallevent_message(const std::tm& Time1, const std::tm& Time2, uint8_t eventType = 2, uint8_t monitorPoint = 1); +/** + * @brief 生成装置心跳报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_requestHeartBeat_message(); +/** + * @brief 生成装置控制命令报文 + * @param type 命令类型 1-装置复位,2-启动录波,3-启动200ms数据记录,4-启动3秒数据记录 + * @param ctrlflag 命令校验 首次传入0 接收校验应答后 0x01执行 0x02取消 + * @return 包含完整报文的字节向量 + */ +std::vector generate_control_message(uint8_t type, uint8_t ctrlflag); + +//////////////////////////////////////////////////////对外接口函数 +RealtagPqDate_float BuildRealPqDataFromJson(cJSON* jsondata, int wiringType); +std::array BuildPqFloatDataFromJson(cJSON* jsondata,int connectionType); +std::string BuildBase64ByTemplate(cJSON* templateRoot, + cJSON* jsondata, + const std::string& dataSetName, + bool isStat, + int statType); +void enqueue_realtime_pq(const RealtagPqDate_float& realdata, + int nPTType, + unsigned char cid, + const std::string& mac, + const std::string& mpid, + int idx); +void enqueue_stat_pq(const std::string& max_base64Str, + const std::string& min_base64Str, + const std::string& avg_base64Str, + const std::string& cp95_base64Str, + time_t data_time, + const std::string& mac, + short cid, + const std::string& mpid); +