From f4c74c7d67231359073e8232cd4c9cae7524205f Mon Sep 17 00:00:00 2001 From: zw <3466561528@qq.com> Date: Wed, 3 Sep 2025 08:49:38 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A3=85=E7=BD=AE=E8=BF=90=E8=A1=8C=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=8A=A5=E6=96=87=E4=B8=8E=E8=A3=85=E7=BD=AE=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E9=85=8D=E7=BD=AE=E4=BF=A1=E6=81=AF=E6=8A=A5=E6=96=87?= =?UTF-8?q?=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LFtid1056/PQSMsg.cpp | 34 ++- LFtid1056/PQSMsg.h | 18 +- LFtid1056/client2.cpp | 65 +++++ LFtid1056/client2.h | 11 + LFtid1056/dealMsg.cpp | 573 +++++++++++++++++++++++++++++++++++++- LFtid1056/main_thread.cpp | 22 +- 6 files changed, 708 insertions(+), 15 deletions(-) diff --git a/LFtid1056/PQSMsg.cpp b/LFtid1056/PQSMsg.cpp index ebf0ce4..68a8d9d 100644 --- a/LFtid1056/PQSMsg.cpp +++ b/LFtid1056/PQSMsg.cpp @@ -352,7 +352,7 @@ std::vector generate_frontlogin_message(const std::string& strMac //GetMAC(strMac, packet, 20); //lnk20250808 std::string err; - if (!GetMAC(strMac, packet, 0, &err)) { + if (!GetMAC(strMac, packet, 20, &err)) { std::cerr << "[GetMAC] parse failed: " << err << "\n"; // 做降级或返回 } @@ -622,4 +622,36 @@ std::vector generate_requestsetinterfixvalue_message_new(const st // 调用通用报文生成函数 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Set_InterFix)); +} + +/** + * @brief 生成装置运行信息读取指令报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_machinestatus_message() +{ + // 创建10字节数据缓冲区,初始化为0 + std::vector DataBuf(10, 0x00); + + // 设置索引3的值为1(第4个字节) + DataBuf[3] = 0x01; + + // 调用通用报文生成函数,功能码14对应装置状态读取 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Read_RunningInformation)); +} + +/** + * @brief 生成装置版本配置信息读取指令报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_machineversion_message() +{ + // 创建10字节数据缓冲区,初始化为0 + std::vector DataBuf(10, 0x00); + + // 设置索引3的值为1(第4个字节) + DataBuf[3] = 0x02; + + // 调用通用报文生成函数,功能码14对应装置状态读取 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Read_RunningInformation)); } \ No newline at end of file diff --git a/LFtid1056/PQSMsg.h b/LFtid1056/PQSMsg.h index 71b9f8a..68d62e5 100644 --- a/LFtid1056/PQSMsg.h +++ b/LFtid1056/PQSMsg.h @@ -39,7 +39,9 @@ enum class MsgRequestType : unsigned char { //询问内部定值描述 内部定值or控制字 Request_Read_InterFixDes = 0x24, //设置内部定值 - Request_Set_InterFix = 0x25 + Request_Set_InterFix = 0x25, + //询问装置运行信息 + Request_Read_RunningInformation = 0x0e }; // 接收报文功能码枚举 enum class MsgResponseType : unsigned char { @@ -69,6 +71,8 @@ enum class MsgResponseType : unsigned char { Response_Read_InterFixDes = 0xA4, //设置内部定值(未使用,采用默认肯定与否定应答) Response_Set_InterFix = 0xA5, + //询问装置运行信息 + Response_Read_RunningInformation = 0x8e, //默认肯定应答 Response_NewACK = 0x40, //默认否定应答 @@ -2165,4 +2169,14 @@ std::vector generate_requestinterfixdes_message(unsigned char nDe * @return 包含完整报文的字节向量 */ std::vector generate_requestsetinterfixvalue_message(const std::vector& values); -std::vector generate_requestsetinterfixvalue_message_new(const std::vector& value); \ No newline at end of file +std::vector generate_requestsetinterfixvalue_message_new(const std::vector& value); +/** + * @brief 生成装置运行信息读取指令报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_machinestatus_message(); +/** + * @brief 生成装置版本配置信息读取指令报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_machineversion_message(); \ No newline at end of file diff --git a/LFtid1056/client2.cpp b/LFtid1056/client2.cpp index eea3622..f05efda 100644 --- a/LFtid1056/client2.cpp +++ b/LFtid1056/client2.cpp @@ -377,6 +377,7 @@ void on_timer(uv_timer_t* handle) { ctx->add_action(DeviceState::READING_STATS_TIME, sendbuff);//灏嗚鐘舵佷互鍙婂緟鍙戦佹姤鏂囧瓨鍏ラ槦鍒 } //涓绉掍竴娆 鎵ц瀹炴椂鏁版嵁璇㈤棶 浠呮墽琛屾寚瀹氭鏁 + now = uv_now(ctx->loop); if (ctx->current_state_ == DeviceState::IDLE && now - ctx->real_state_query_time_ >= 1000 && ctx->real_state_count > 0) { // 鏇存柊瀹炴椂鏁版嵁鎵ц鏃堕棿鍜屽疄鏃舵敹鍙戣鏁 ctx->real_state_query_time_ = now; @@ -385,6 +386,16 @@ void on_timer(uv_timer_t* handle) { auto sendbuff = generate_realstat_message(static_cast(ctx->real_point_id_), static_cast(0x01), static_cast(0x01));//缁勮璇㈤棶瀹炴椂鏁版嵁鎶ユ枃 ctx->add_action(DeviceState::READING_REALSTAT, sendbuff);//灏嗚鐘舵佷互鍙婂緟鍙戦佹姤鏂囧瓨鍏ラ槦鍒 } + //30鍒嗛挓涓娆 璇诲彇瑁呯疆杩愯淇℃伅 + now = uv_now(ctx->loop); + if (ctx->current_state_ == DeviceState::IDLE && now - ctx->read_runninginformationMsg >= 60000 * 30) + { + // 鏇存柊杩愯淇℃伅鏈鍚庤鍙栨椂闂 + ctx->read_runninginformationMsg = now; + + auto sendbuff = generate_machinestatus_message();//缁勮璇诲彇瑁呯疆杩愯淇℃伅鎶ユ枃 + ctx->add_action(DeviceState::READING_RUNNINGINFORMATION_2, sendbuff);//灏嗚鐘舵佷互鍙婂緟鍙戦佹姤鏂囧瓨鍏ラ槦鍒 + } //澶勭悊鍚庣画宸ヤ綔闃熷垪鐨勫伐浣 鍙栧嚭涓涓苟鎵ц if (ctx->current_state_ == DeviceState::IDLE) { ctx->process_next_action(); @@ -530,6 +541,7 @@ void on_connect(uv_connect_t* req, int status) { // 鏂板锛氬垵濮嬪寲鍚勪釜璁℃椂鏃堕棿鎴 ctx->last_state_query_time_ = uv_now(ctx->loop);//鍒濆鍖栫粺璁℃暟鎹椂闂存埑 ctx->real_state_query_time_ = uv_now(ctx->loop);//鍒濆鍖栧疄鏃舵暟鎹椂闂存埑 + ctx->read_runninginformationMsg = uv_now(ctx->loop);//鍒濆鍖栬鍙栬缃繍琛屼俊鎭椂闂存埑 ctx->real_state_count = 0;//瀹炴椂鏁版嵁鏀跺彂璁℃暟 //瀹㈡埛绔繛鎺ュ畬姣曞悗锛屽彂閫佽缃櫥闄嗘秷鎭 std::cout << "connected: " << ctx->device_info.mac << " send login msg!" << std::endl; @@ -1250,6 +1262,59 @@ bool ClientManager::set_interfixedvalue_action_to_device(const std::string& iden return false; // 璁惧鏈壘鍒 } +//璇诲彇瑁呯疆杩愯淇℃伅 +bool ClientManager::read_runninginformation_action_to_device(const std::string& identifier) { + std::lock_guard lock(mutex_); + + // 鏌ユ壘鍖归厤鐨勮澶 + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) + { + // 鐢熸垚瀹氬兼弿杩版姤鏂 + auto packet = generate_machinestatus_message(); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::READING_RUNNINGINFORMATION_1, packet); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +//璇诲彇瑁呯疆鐗堟湰閰嶇疆淇℃伅 +bool ClientManager::read_devversion_action_to_device(const std::string& identifier) { + std::lock_guard lock(mutex_); + + // 鏌ユ壘鍖归厤鐨勮澶 + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) + { + // 鐢熸垚瀹氬兼弿杩版姤鏂 + auto packet = generate_machineversion_message(); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::READING_DEVVERSION, packet); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} //鑾峰彇鎸囧畾瑁呯疆娴嬬偣鐨勭數鍘嬬瓑绾т笌鎺ョ嚎鏂瑰紡 bool ClientManager::get_point_scale_and_pttype(const std::string& identifier, ushort nCpuNo, diff --git a/LFtid1056/client2.h b/LFtid1056/client2.h index 8605ca9..db3f453 100644 --- a/LFtid1056/client2.h +++ b/LFtid1056/client2.h @@ -32,6 +32,7 @@ struct DeviceInfo { std::string mac; // 装置MAC地址 int status; // 运行状态 (0: 离线, 1: 在线) std::vector points; // 下属测点 + bool righttime; //对时启动标志 }; enum class ConnectionState { @@ -56,6 +57,9 @@ enum class DeviceState { READING_INTERFIXEDVALUEDES, // 读取内部定值描述 READING_CONTROLWORD, // 读取控制字描述 SET_INTERFIXEDVALUE, // 设置内部定值 + READING_RUNNINGINFORMATION_1,// 读取装置运行信息(主动触发) + READING_RUNNINGINFORMATION_2,// 读取装置运行信息(定时执行) + READING_DEVVERSION, // 读取装置版本配置信息 // 可根据需要添加更多状态 CUSTOM_ACTION // 自定义动作 }; @@ -79,6 +83,7 @@ public: uint64_t real_state_query_time_ = 0; // 实时数据计时时间戳 std::atomic real_state_count{ 0 };//实时数据收发计数 原子操作保证线程安全 std::atomic real_point_id_{ 1 }; // 新增:实时数据读取的测点序号(原子操作) + uint64_t read_runninginformationMsg = 0; // 装置定时读取运行信息时间戳 DeviceInfo device_info; // 装置信息 int cloudstatus; // 云前置登录状态(0:未登录 1:已登录) @@ -395,6 +400,12 @@ public: //设置装置内部定值 传入mac/id + 内部定值序列 bool set_interfixedvalue_action_to_device(const std::string& identifier, const std::vector& values); + + //读取装置运行信息 + bool read_runninginformation_action_to_device(const std::string& identifier); + + //读取装置版本配置信息 + bool read_devversion_action_to_device(const std::string& identifier); private: ClientManager() : loop_(nullptr) {} std::unordered_map> clients_; diff --git a/LFtid1056/dealMsg.cpp b/LFtid1056/dealMsg.cpp index 10f3599..f0f5613 100644 --- a/LFtid1056/dealMsg.cpp +++ b/LFtid1056/dealMsg.cpp @@ -79,6 +79,8 @@ void process_received_message(string mac, string id,const char* data, size_t len //ClientManager::instance().get_interfixedvalue_action_to_device(id);//装置获取内部定值 //ClientManager::instance().get_fixedvalucontrolword_action_to_device(id,1);//获取 1-内部定值描述 或者 2-控制字描述 //ClientManager::instance().set_interfixedvalue_action_to_device();装置修改内部定值测试(参数由外部提供) + //ClientManager::instance().read_runninginformation_action_to_device(id);//主动触发,读取装置运行信息 + ClientManager::instance().read_devversion_action_to_device(id);//主动触发,读取装置版本配置信息 } if (udata[19] == 0x00) { std::cout << "cloud login: " << mac << " state: fail!" << std::endl; @@ -97,7 +99,7 @@ void process_received_message(string mac, string id,const char* data, size_t len //装置主动上送报文 暂态事件报文/暂态波形文件报文 if (udata[8] == static_cast(MsgResponseType::Response_Event)) { //处理主动上送的暂态事件报文 - NewTaglogbuffer event = NewTaglogbuffer::createFromData(parser.RecvData.data(), parser.RecvData.size()); + NewTaglogbuffer event = NewTaglogbuffer::createFromData(parser.RecvData.data(), parser.RecvData.size()); // 获取测点参数 std::string strScale;//电压等级 @@ -1179,6 +1181,575 @@ void process_received_message(string mac, string id,const char* data, size_t len } break; + case DeviceState::READING_RUNNINGINFORMATION_1: + //读取装置运行信息(主动触发) + if (udata[8] == static_cast(MsgResponseType::Response_Read_RunningInformation)) { + // 获取解析后的数据体 + std::vector& recvData = parser.RecvData; + + // 检查数据长度是否足够 + if (recvData.size() < 2) { + std::cerr << "Invalid running information data: too short (" + << recvData.size() << " bytes)" << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 提取有效载荷长度 + size_t payloadLength = recvData.size() - 2; + + // 复制有效载荷数据 + std::vector payloadBytes(payloadLength); + if (recvData.size() >= 2 + payloadLength) { + std::copy(recvData.begin() + 2, recvData.begin() + 2 + payloadLength, payloadBytes.begin()); + } + else { + std::cerr << "Invalid payload length: " << payloadLength + << ", available: " << (recvData.size() - 2) << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 转换为UTF-8字符串 + std::string payload(payloadBytes.begin(), payloadBytes.end()); + + // 定义类似New_MachMessage的结构体 + struct RunningInformation { + std::string Time; + std::string CpuLoad; + std::string FreeMemory; + std::string TotalMemory; + std::string FreeStorage; + std::string TotalStorage; + std::string HardTimeSync; + std::string SntpTimeSync; + std::string CloudTimeSync; + std::string SignalStrength; + } result; + + // 辅助函数:去除字符串两端的引号 + auto trimQuotes = [](const std::string& str) -> std::string { + if (str.size() >= 2 && str.front() == '"' && str.back() == '"') { + return str.substr(1, str.size() - 2); + } + return str; + }; + + // 辅助函数:处理CPU负载值 + auto processCpuLoad = [](const std::string& cpuValue) -> std::string { + if (cpuValue.empty()) return cpuValue; + + // 处理多核格式(如"39_38") + if (cpuValue.find('_') != std::string::npos) { + std::vector cores; + size_t start = 0, end; + while ((end = cpuValue.find('_', start)) != std::string::npos) { + cores.push_back(cpuValue.substr(start, end - start)); + start = end + 1; + } + cores.push_back(cpuValue.substr(start)); // 添加最后一部分 + + for (auto& core : cores) { + // 手动转换整数(替代std::stoi) + const char* str = core.c_str(); + char* endptr = nullptr; + long value = strtol(str, &endptr, 10); + + // 检查转换是否有效 + if (endptr != str && *endptr == '\0') { + // 校正超范围值 + if (value > 100) value /= 100; + core = std::to_string(value); + } + // 转换失败保持原值 + } + + std::string result; + for (size_t i = 0; i < cores.size(); ++i) { + if (i > 0) result += '_'; + result += cores[i]; + } + return result; + } + // 处理单核格式 + else { + const char* str = cpuValue.c_str(); + char* endptr = nullptr; + long value = strtol(str, &endptr, 10); + + // 检查转换是否有效 + if (endptr != str && *endptr == '\0') { + if (value > 100) value /= 100; + return std::to_string(value); + } + return cpuValue; + } + }; + + // 分割字段并处理 + std::vector fields; + size_t start = 0; + while (start < payload.length()) { + size_t end = payload.find(',', start); + if (end == std::string::npos) { + fields.push_back(payload.substr(start)); + break; + } + fields.push_back(payload.substr(start, end - start)); + start = end + 1; + } + + for (const auto& field : fields) { + // 跳过空字段 + if (field.empty()) continue; + + // 查找冒号位置 + size_t colonPos = field.find(':'); + if (colonPos == std::string::npos || colonPos == 0 || colonPos == field.length() - 1) { + continue; + } + + // 分割键值对 + std::string key = field.substr(0, colonPos); + std::string value = field.substr(colonPos + 1); + + // 去除键的空白 + size_t keyStart = key.find_first_not_of(" \t"); + size_t keyEnd = key.find_last_not_of(" \t"); + if (keyStart != std::string::npos && keyEnd != std::string::npos) { + key = key.substr(keyStart, keyEnd - keyStart + 1); + } + + // 去除值的空白 + size_t valStart = value.find_first_not_of(" \t"); + size_t valEnd = value.find_last_not_of(" \t"); + if (valStart != std::string::npos && valEnd != std::string::npos) { + value = value.substr(valStart, valEnd - valStart + 1); + } + + // 去除值两端的引号 + if (value.size() >= 2 && value.front() == '"' && value.back() == '"') { + value = value.substr(1, value.size() - 2); + } + + // 尝试将键转换为整数 + const char* keyStr = key.c_str(); + char* endPtr = nullptr; + long fieldId = strtol(keyStr, &endPtr, 10); + + // 检查转换是否有效 + if (endPtr != keyStr && *endPtr == '\0' && fieldId >= 1 && fieldId <= 10) { + switch (fieldId) { + case 1: result.Time = value; break; + case 2: result.CpuLoad = value; break; + case 3: result.FreeMemory = value; break; + case 4: result.TotalMemory = value; break; + case 5: result.FreeStorage = value; break; + case 6: result.TotalStorage = value; break; + case 7: result.HardTimeSync = value; break; + case 8: result.SntpTimeSync = value; break; + case 9: result.CloudTimeSync = value; break; + case 10: result.SignalStrength = value; break; + default: break; + } + } + } + + // 特殊处理CPU负载 + result.CpuLoad = processCpuLoad(result.CpuLoad); + + // 打印解析结果(实际应用中可替换为其他处理逻辑) + std::cout << "Device Running Information (" << mac << "):\n" + << " Time: " << result.Time << "\n" + << " CPU Load: " << result.CpuLoad << "\n" + << " Memory: " << result.FreeMemory << "/" << result.TotalMemory << " MB\n" + << " Storage: " << result.FreeStorage << "/" << result.TotalStorage << " GB\n" + << " Time Sync: Hard=" << result.HardTimeSync + << ", SNTP=" << result.SntpTimeSync + << ", Cloud=" << result.CloudTimeSync << "\n" + << " Signal: " << result.SignalStrength << std::endl; + + //读取装置运行信息(主动触发)成功,调整为空闲,处理后续工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 读取装置运行信息(主动触发)失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::READING_RUNNINGINFORMATION_2: + //读取装置运行信息(定时触发) 接收与解析和主动触发一致,仅修改数据发送部分 + if (udata[8] == static_cast(MsgResponseType::Response_Read_RunningInformation)) { + // 获取解析后的数据体 + std::vector& recvData = parser.RecvData; + + // 检查数据长度是否足够 + if (recvData.size() < 2) { + std::cerr << "Invalid running information data: too short (" + << recvData.size() << " bytes)" << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 提取有效载荷长度 + size_t payloadLength = recvData.size() - 2; + + // 复制有效载荷数据 + std::vector payloadBytes(payloadLength); + if (recvData.size() >= 2 + payloadLength) { + std::copy(recvData.begin() + 2, recvData.begin() + 2 + payloadLength, payloadBytes.begin()); + } + else { + std::cerr << "Invalid payload length: " << payloadLength + << ", available: " << (recvData.size() - 2) << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 转换为UTF-8字符串 + std::string payload(payloadBytes.begin(), payloadBytes.end()); + + // 定义类似New_MachMessage的结构体 + struct RunningInformation { + std::string Time; + std::string CpuLoad; + std::string FreeMemory; + std::string TotalMemory; + std::string FreeStorage; + std::string TotalStorage; + std::string HardTimeSync; + std::string SntpTimeSync; + std::string CloudTimeSync; + std::string SignalStrength; + } result; + + // 辅助函数:去除字符串两端的引号 + auto trimQuotes = [](const std::string& str) -> std::string { + if (str.size() >= 2 && str.front() == '"' && str.back() == '"') { + return str.substr(1, str.size() - 2); + } + return str; + }; + + // 辅助函数:处理CPU负载值 + auto processCpuLoad = [](const std::string& cpuValue) -> std::string { + if (cpuValue.empty()) return cpuValue; + + // 处理多核格式(如"39_38") + if (cpuValue.find('_') != std::string::npos) { + std::vector cores; + size_t start = 0, end; + while ((end = cpuValue.find('_', start)) != std::string::npos) { + cores.push_back(cpuValue.substr(start, end - start)); + start = end + 1; + } + cores.push_back(cpuValue.substr(start)); // 添加最后一部分 + + for (auto& core : cores) { + // 手动转换整数(替代std::stoi) + const char* str = core.c_str(); + char* endptr = nullptr; + long value = strtol(str, &endptr, 10); + + // 检查转换是否有效 + if (endptr != str && *endptr == '\0') { + // 校正超范围值 + if (value > 100) value /= 100; + core = std::to_string(value); + } + // 转换失败保持原值 + } + + std::string result; + for (size_t i = 0; i < cores.size(); ++i) { + if (i > 0) result += '_'; + result += cores[i]; + } + return result; + } + // 处理单核格式 + else { + const char* str = cpuValue.c_str(); + char* endptr = nullptr; + long value = strtol(str, &endptr, 10); + + // 检查转换是否有效 + if (endptr != str && *endptr == '\0') { + if (value > 100) value /= 100; + return std::to_string(value); + } + return cpuValue; + } + }; + + // 分割字段并处理 + std::vector fields; + size_t start = 0; + while (start < payload.length()) { + size_t end = payload.find(',', start); + if (end == std::string::npos) { + fields.push_back(payload.substr(start)); + break; + } + fields.push_back(payload.substr(start, end - start)); + start = end + 1; + } + + for (const auto& field : fields) { + // 跳过空字段 + if (field.empty()) continue; + + // 查找冒号位置 + size_t colonPos = field.find(':'); + if (colonPos == std::string::npos || colonPos == 0 || colonPos == field.length() - 1) { + continue; + } + + // 分割键值对 + std::string key = field.substr(0, colonPos); + std::string value = field.substr(colonPos + 1); + + // 去除键的空白 + size_t keyStart = key.find_first_not_of(" \t"); + size_t keyEnd = key.find_last_not_of(" \t"); + if (keyStart != std::string::npos && keyEnd != std::string::npos) { + key = key.substr(keyStart, keyEnd - keyStart + 1); + } + + // 去除值的空白 + size_t valStart = value.find_first_not_of(" \t"); + size_t valEnd = value.find_last_not_of(" \t"); + if (valStart != std::string::npos && valEnd != std::string::npos) { + value = value.substr(valStart, valEnd - valStart + 1); + } + + // 去除值两端的引号 + if (value.size() >= 2 && value.front() == '"' && value.back() == '"') { + value = value.substr(1, value.size() - 2); + } + + // 尝试将键转换为整数 + const char* keyStr = key.c_str(); + char* endPtr = nullptr; + long fieldId = strtol(keyStr, &endPtr, 10); + + // 检查转换是否有效 + if (endPtr != keyStr && *endPtr == '\0' && fieldId >= 1 && fieldId <= 10) { + switch (fieldId) { + case 1: result.Time = value; break; + case 2: result.CpuLoad = value; break; + case 3: result.FreeMemory = value; break; + case 4: result.TotalMemory = value; break; + case 5: result.FreeStorage = value; break; + case 6: result.TotalStorage = value; break; + case 7: result.HardTimeSync = value; break; + case 8: result.SntpTimeSync = value; break; + case 9: result.CloudTimeSync = value; break; + case 10: result.SignalStrength = value; break; + default: break; + } + } + } + + // 特殊处理CPU负载 + result.CpuLoad = processCpuLoad(result.CpuLoad); + + // 打印解析结果(实际应用中可替换为其他处理逻辑) + std::cout << "Device Running Information (" << mac << "):\n" + << " Time: " << result.Time << "\n" + << " CPU Load: " << result.CpuLoad << "\n" + << " Memory: " << result.FreeMemory << "/" << result.TotalMemory << " MB\n" + << " Storage: " << result.FreeStorage << "/" << result.TotalStorage << " GB\n" + << " Time Sync: Hard=" << result.HardTimeSync + << ", SNTP=" << result.SntpTimeSync + << ", Cloud=" << result.CloudTimeSync << "\n" + << " Signal: " << result.SignalStrength << std::endl; + + //读取装置运行信息(主动触发)成功,调整为空闲,处理后续工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 读取装置运行信息(定时触发)失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::READING_DEVVERSION: + //读取装置版本配置信息(功能码同运行信息读取)(运维协议确认对时版本,电度与高频谐波开关,稳态间隔获取,版本配置上送) + if (udata[8] == static_cast(MsgResponseType::Response_Read_RunningInformation)) { + // 获取解析后的数据体 + std::vector& recvData = parser.RecvData; + + // 检查数据长度是否足够 + if (recvData.size() < 2) { + std::cerr << "Invalid running information data: too short (" + << recvData.size() << " bytes)" << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 提取有效载荷长度 + size_t payloadLength = recvData.size() - 2; + + // 复制有效载荷数据 + std::vector payloadBytes(payloadLength); + if (recvData.size() >= 2 + payloadLength) { + std::copy(recvData.begin() + 2, recvData.begin() + 2 + payloadLength, payloadBytes.begin()); + } + else { + std::cerr << "Invalid payload length: " << payloadLength + << ", available: " << (recvData.size() - 2) << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 转换为UTF-8字符串 + std::string payload(payloadBytes.begin(), payloadBytes.end()); + + // 定义存储装置版本信息的结构体 + struct DeviceVersionInfo { + std::string BaseModel; // 1: 装置基础型号 + std::string CloudProtocolVer; // 2: 云服务协议版本 + std::string AppVersion; // 3: 应用程序版本号 + std::string AppDate; // 4: 应用程序版本日期 + std::string AppChecksum; // 5: 应用程序校验码 + std::string VoltageWiring; // 6: 电压接线方式 + std::string CurrentBSynthetic; // 7: 电流B相是否合成 + int DataStatInterval = 0; // 8: 数据统计时间间隔(分钟) + float RatedVoltage = 0.0f; // 9: 额定电压(二次值,单位V) + float PTRatio = 0.0f; // 10: PT变比 + float CTRatio = 0.0f; // 11: CT变比 + std::string SntpIP; // 12: sntp对时IP + int SntpPort = 0; // 13: sntp对时端口 + int SntpInterval = 0; // 14: sntp对时间隔(分钟) + int WebPort = 0; // 15: Web端口 + int FtpPort = 0; // 16: ftp端口 + int PqdifInterval = 0; // 17: Pqdif文件时间间隔(小时) + int WaveFileTypeCount = 0; // 18: 录波文件包含文件类型数 + std::string SpecialVersion; // 19: 特殊程序版本信息 + std::string DeviceModel; // 20: 装置型号 + int HarmonicEnergyFlag = 0; // 21: 谐波电度版本标志 + std::string PhysicalName; // 22: 物理设备名称 + std::string WaveLDName; // 23: 录波LD名称 + int HighFreqHarmonicFlag = 0; // 24: 高频谐波功能标志 + unsigned int CommProtocols = 0; // 51: 投入的通讯协议 + unsigned int TimeSyncMethods = 0;// 52: 投入的对时方式 + unsigned int DeviceFunctions = 0;// 53: 装置功能配置 + } versionInfo; + + // 分割字段 + std::vector fields; + size_t start = 0; + while (start < payload.length()) { + size_t end = payload.find(',', start); + if (end == std::string::npos) { + fields.push_back(payload.substr(start)); + break; + } + fields.push_back(payload.substr(start, end - start)); + start = end + 1; + } + + // 处理每个字段 + for (const auto& field : fields) { + if (field.empty()) continue; + + // 分割键值对 + size_t colonPos = field.find(':'); + if (colonPos == std::string::npos || colonPos == 0) continue; + + std::string key = field.substr(0, colonPos); + std::string value = field.substr(colonPos + 1); + + // 去除键值两端的空白和引号 + auto trim = [](std::string str) -> std::string { + size_t start = str.find_first_not_of(" \t\""); + size_t end = str.find_last_not_of(" \t\""); + return (start == std::string::npos) ? "" : str.substr(start, end - start + 1); + }; + key = trim(key); + value = trim(value); + + // 转换为信息编码ID + try { + int fieldId = std::stoi(key); + switch (fieldId) { + // 字符串类型字段 + case 1: versionInfo.BaseModel = value; break; + case 2: versionInfo.CloudProtocolVer = value; break; + case 3: versionInfo.AppVersion = value; break; + case 4: versionInfo.AppDate = value; break; + case 5: versionInfo.AppChecksum = value; break; + case 6: versionInfo.VoltageWiring = value; break; + case 7: versionInfo.CurrentBSynthetic = value; break; + case 12: versionInfo.SntpIP = value; break; + case 19: versionInfo.SpecialVersion = value; break; + case 20: versionInfo.DeviceModel = value; break; + case 22: versionInfo.PhysicalName = value; break; + case 23: versionInfo.WaveLDName = value; break; + + // 数值类型字段 + case 8: versionInfo.DataStatInterval = std::stoi(value); break; + case 9: versionInfo.RatedVoltage = std::stof(value); break; + case 10: versionInfo.PTRatio = std::stof(value); break; + case 11: versionInfo.CTRatio = std::stof(value); break; + case 13: versionInfo.SntpPort = std::stoi(value); break; + case 14: versionInfo.SntpInterval = std::stoi(value); break; + case 15: versionInfo.WebPort = std::stoi(value); break; + case 16: versionInfo.FtpPort = std::stoi(value); break; + case 17: versionInfo.PqdifInterval = std::stoi(value); break; + case 18: versionInfo.WaveFileTypeCount = std::stoi(value); break; + case 21: versionInfo.HarmonicEnergyFlag = std::stoi(value); break; + case 24: versionInfo.HighFreqHarmonicFlag = std::stoi(value); break; + + // 十六进制字段(51+) + case 51: + case 52: + case 53: { + if (value.size() > 2 && value.substr(0, 2) == "0x") { + unsigned int hexValue = std::stoul(value.substr(2), nullptr, 16); + switch (fieldId) { + case 51: versionInfo.CommProtocols = hexValue; break; + case 52: versionInfo.TimeSyncMethods = hexValue; break; + case 53: versionInfo.DeviceFunctions = hexValue; break; + } + } + break; + } + } + } + catch (const std::exception& e) { + std::cerr << "Error parsing field: " << field + << ", error: " << e.what() << std::endl; + } + } + + // 打印解析结果 + std::cout << "Device Version Info (" << mac << "):\n" + << " Base Model: " << versionInfo.BaseModel << "\n" + << " Cloud Protocol: " << versionInfo.CloudProtocolVer << "\n" + << " App Version: " << versionInfo.AppVersion << "\n" + << " App Date: " << versionInfo.AppDate << "\n" + << " PT Ratio: " << versionInfo.PTRatio << "\n" + << " CT Ratio: " << versionInfo.CTRatio << "\n" + << " Wave File Types: " << versionInfo.WaveFileTypeCount << "\n" + << " Comm Protocols: 0x" << std::hex << versionInfo.CommProtocols << "\n" + << " Time Sync Methods: 0x" << versionInfo.TimeSyncMethods << "\n" + << " Device Functions: 0x" << versionInfo.DeviceFunctions << std::dec << "\n"; + + //读取装置版本配置信息成功,调整为空闲,处理后续工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 读取装置版本配置信息失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + case DeviceState::CUSTOM_ACTION: // 自定义动作状态 std::cout << "CUSTOM_ACTION state: Processing custom response from " << mac << std::endl; diff --git a/LFtid1056/main_thread.cpp b/LFtid1056/main_thread.cpp index 8466563..9515631 100644 --- a/LFtid1056/main_thread.cpp +++ b/LFtid1056/main_thread.cpp @@ -154,27 +154,27 @@ void* client_manager_thread(void* arg) { printf("Started client connections\n"); // 创建测点数据 - /*std::vector points1 = { + std::vector points1 = { {"P001", "Main Voltage", "D001",1 ,1, 1, 1, 1,"0.38k",0}, {"P002", "Backup Voltage", "D001",2 ,1, 1, 1, 1,"0.38k",0} }; //00B78DA800D6 00-B7-8D-01-79-06 // 创建装置列表 - /*std::vector devices = { + std::vector devices = { { "D001", "Primary Device", "Model-X", "00-B7-8D-01-79-06", - 1, points1 + 1, points1,true } - };*/ + }; // 生成100个测试装置 //std::vector test_devices = generate_test_devices(100); //lnk从台账读取设备 - std::vector devices = GenerateDeviceInfoFromLedger(terminal_devlist);//lnk添加 + //std::vector devices = GenerateDeviceInfoFromLedger(terminal_devlist);//lnk添加 //台账打印 - PrintDevices(devices); + //PrintDevices(devices); // 启动客户端连接 start_client_connect(devices); @@ -319,10 +319,10 @@ int main(int argc ,char** argv) {// cleanup_args(args); } - while(!INITFLAG){ + /*while(!INITFLAG){ std::this_thread::sleep_for(std::chrono::seconds(3)); std::cout << "waiting cloudfront initialize ..." << std::endl; - } + }*/ // 创建初始线程组 for (int i = 1; i < THREAD_CONNECTIONS; i++) { @@ -396,7 +396,7 @@ int main(int argc ,char** argv) {// std::vector devices = { { "D002", "Backup Device", "Model-Y", "00-B7-8D-A8-00-D6", - 1, points2 + 1, points2,true } }; @@ -405,10 +405,10 @@ int main(int argc ,char** argv) {// //static int count = 3; if (++queue_monitor >= 20) { // 尝试添加一个设备 printf("Message queue size: %zu\n", message_queue.size()); - //queue_monitor = 0; + queue_monitor = 0; for (const auto& device : devices) { - ClientManager::instance().add_device(device); + //ClientManager::instance().add_device(device); } /*std::vector test_devices = generate_test_devices(count);