diff --git a/LFtid1056.rar b/LFtid1056.rar index 42600d7..966afb3 100644 Binary files a/LFtid1056.rar and b/LFtid1056.rar differ diff --git a/LFtid1056/cloudfront/code/cfg_parser.cpp b/LFtid1056/cloudfront/code/cfg_parser.cpp index 562dbf2..dbdb26c 100644 --- a/LFtid1056/cloudfront/code/cfg_parser.cpp +++ b/LFtid1056/cloudfront/code/cfg_parser.cpp @@ -69,6 +69,52 @@ extern std::map xmlinfo_list2;//保存所有型号角形 ////////////////////////////////////////////////////////////////////////////////////////////////// extern time_t ConvertToTimestamp(const tagTime& time); +///////////////////////////////////////////////////////////////////////////////////////////////// +// 运行信息 +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; +}; + +// 版本信息 +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 + int DataStatInterval = 0; // 8 + float RatedVoltage = 0.0f; // 9 + float PTRatio = 0.0f; // 10 + float CTRatio = 0.0f; // 11 + std::string SntpIP; // 12 + int SntpPort = 0; // 13 + int SntpInterval = 0; // 14 + int WebPort = 0; // 15 + int FtpPort = 0; // 16 + int PqdifInterval = 0; // 17 + int WaveFileTypeCount = 0; // 18 + std::string SpecialVersion; // 19 + std::string DeviceModel; // 20 + int HarmonicEnergyFlag = 0; // 21 + std::string PhysicalName; // 22 + std::string WaveLDName; // 23 + int HighFreqHarmonicFlag = 0; // 24 + unsigned int CommProtocols = 0; // 51 + unsigned int TimeSyncMethods = 0;// 52 + unsigned int DeviceFunctions = 0;// 53 +}; + //////////////////////////////////////////////////////////////////////////////////////////////////// //补招记录文件 std::mutex g_recall_file_mtx; @@ -78,9 +124,18 @@ std::map, std::string> g_recall_file_index; std::mutex g_last_ts_mtx; std::unordered_map g_last_ts_by_devid; +//目录信息缓存 static std::mutex g_filemenu_cache_mtx; std::map> g_filemenu_cache; +// 运行信息缓存 +static std::mutex g_runninginfo_cache_mtx; +static std::map g_runninginfo_cache; + +// 版本信息缓存 +static std::mutex g_versioninfo_cache_mtx; +static std::map g_versioninfo_cache; + //补招 std::list g_StatisticLackList; //日志补招结构类链表 std::mutex g_StatisticLackList_list_mutex; //补招队列数据锁 @@ -3427,76 +3482,6 @@ std::string normalize_mac(const std::string &mac) { return res; } - -////////////////////////////////////////////////////////////////////////////////////////目录信息发送接口函数 - -bool send_file_list(terminal_dev* dev, const std::vector& FileList) { - - if (!dev) { - std::cerr << "[send_file_list_locked] dev=nullptr\n"; - return false; - } - - // 判断 isbusy==1 且 busytype==READING_FILEMENU - if (dev->isbusy != 1 || dev->busytype != static_cast(DeviceState::READING_FILEMENU)) { - std::cerr << "[send_file_list] device not in READING_FILEMENU state." << std::endl; - return false; - } - - // 构造 JSON 报文 - nlohmann::json j; - j["guid"] = dev->guid; - j["FrontId"] = FRONT_INST; // 这里填你的前置机id - j["Node"] = g_front_seg_index; // 节点号 - j["Dev_mac"] = normalize_mac(dev->addr_str); // addr_str 存的是 MAC - - // 构造 DirInfo 数组 - nlohmann::json dirArray = nlohmann::json::array(); - for (const auto &f : FileList) { - nlohmann::json item; - item["Name"] = f.name; - item["Type"] = (f.flag == 0) ? "dir" : "file"; - item["Size"] = f.size; - dirArray.push_back(item); - } - - // 构造 Detail 部分 - nlohmann::json detail; - detail["Type"] = 0x2131; // 读取目录 - detail["Msg"] = { {"DirInfo", dirArray} }; - detail["Code"] = 200; // 请求成功 - - // 放到顶层 - j["Detail"] = detail; - - // 打印调试 - std::cout << j.dump(4) << std::endl; - - // ---- 入队发送 ---- - queue_data_t connect_info; - connect_info.strTopic = Topic_Reply_Topic; - connect_info.strText = j.dump(); // 序列化为字符串 - connect_info.tag = Topic_Reply_Tag; - connect_info.key = Topic_Reply_Key; - { - std::lock_guard lock(queue_data_list_mutex); - queue_data_list.push_back(std::move(connect_info)); - } - // 调试打印 - std::cout << "[send_file_list] queued: " << j.dump() << std::endl; - - //发送后清除guid和标志 - if (dev->isbusy > 0) { - dev->isbusy--; - } - if(dev->isbusy == 0){ - dev->guid.clear(); - dev->busytype = 0; - } - - return true; -} - /////////////////////////////////////////////////////////////////////////////////////////////////////////////检查云前置终端的mq业务超时 std::string get_type_by_state(int state) { switch (state) { @@ -5687,7 +5672,7 @@ bool enqueue_direct_download(const std::string& dev_id, return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////通讯响应处理 +///////////////////////////////////////////////////////////////////////////////////////////////////////////目录响应处理 void filemenu_cache_put(const std::string& dev_id, std::vector FileList) @@ -5707,20 +5692,276 @@ bool filemenu_cache_take(const std::string& dev_id, std::vector& o return true; } -// 提取文件名列表(仅 flag==1) -static inline void build_file_name_list(const std::vector& in, - std::list& out) -{ - out.clear(); - for (const auto& e : in) { - if (e.flag == 1) { - // 安全地从固定长度 char[64] 转成 std::string - size_t n = ::strnlen(e.name, sizeof(e.name)); - out.emplace_back(std::string(e.name, n)); - } +////////////////////////////////////////////////////////////////////////////////////////目录信息发送接口函数 + +bool send_file_list(terminal_dev* dev, const std::vector& FileList) { + + if (!dev) { + std::cerr << "[send_file_list_locked] dev=nullptr\n"; + return false; } + + // 判断 isbusy==1 且 busytype==READING_FILEMENU + if (dev->isbusy != 1 || dev->busytype != static_cast(DeviceState::READING_FILEMENU)) { + std::cerr << "[send_file_list] device not in READING_FILEMENU state." << std::endl; + return false; + } + + // 构造 JSON 报文 + nlohmann::json j; + j["guid"] = dev->guid; + j["FrontId"] = FRONT_INST; // 这里填你的前置机id + j["Node"] = g_front_seg_index; // 节点号 + j["Dev_mac"] = normalize_mac(dev->addr_str); // addr_str 存的是 MAC + + // 构造 DirInfo 数组 + nlohmann::json dirArray = nlohmann::json::array(); + for (const auto &f : FileList) { + nlohmann::json item; + item["Name"] = f.name; + item["Type"] = (f.flag == 0) ? "dir" : "file"; + item["Size"] = f.size; + dirArray.push_back(item); + } + + // 构造 Detail 部分 + nlohmann::json detail; + detail["Type"] = 0x2131; // 读取目录 + detail["Msg"] = { {"DirInfo", dirArray} }; + detail["Code"] = 200; // 请求成功 + + // 放到顶层 + j["Detail"] = detail; + + // 打印调试 + std::cout << j.dump(4) << std::endl; + + // ---- 入队发送 ---- + queue_data_t connect_info; + connect_info.strTopic = Topic_Reply_Topic; + connect_info.strText = j.dump(); // 序列化为字符串 + connect_info.tag = Topic_Reply_Tag; + connect_info.key = Topic_Reply_Key; + { + std::lock_guard lock(queue_data_list_mutex); + queue_data_list.push_back(std::move(connect_info)); + } + // 调试打印 + std::cout << "[send_file_list] queued: " << j.dump() << std::endl; + + //发送后清除guid和标志 + if (dev->isbusy > 0) { + dev->isbusy--; + } + if(dev->isbusy == 0){ + dev->guid.clear(); + dev->busytype = 0; + } + + return true; } +////////////////////////////////////////////////////////////////////////////////////////////////////////运行日志相应处理 + + +void runninginfo_cache_put(const std::string& dev_id, const RunningInformation& info) +{ + std::lock_guard lk(g_runninginfo_cache_mtx); + g_runninginfo_cache[dev_id] = info; +} + +bool runninginfo_cache_take(const std::string& dev_id, RunningInformation& out) +{ + std::lock_guard lk(g_runninginfo_cache_mtx); + auto it = g_runninginfo_cache.find(dev_id); + if (it == g_runninginfo_cache.end()) { + return false; + } + + out = std::move(it->second); + g_runninginfo_cache.erase(it); + return true; +} + +bool send_running_info(terminal_dev* dev, const RunningInformation& info) { + + if (!dev) { + std::cerr << "[send_running_info] dev=nullptr\n"; + return false; + } + + // 判断 isbusy==1 且 busytype==READING_RUNNINGINFO + if (dev->isbusy != 1 || dev->busytype != static_cast(DeviceState::READING_RUNNINGINFO)) { + std::cerr << "[send_running_info] device not in READING_RUNNINGINFO state." << std::endl; + return false; + } + + // 构造 JSON 报文 + nlohmann::json j; + j["guid"] = dev->guid; + j["FrontId"] = FRONT_INST; + j["Node"] = g_front_seg_index; + j["Dev_mac"] = normalize_mac(dev->addr_str); + + // 构造 result + nlohmann::json result; + result["Time"] = info.Time; + result["CpuLoad"] = info.CpuLoad; + result["FreeMemory"] = info.FreeMemory; + result["TotalMemory"] = info.TotalMemory; + result["FreeStorage"] = info.FreeStorage; + result["TotalStorage"] = info.TotalStorage; + result["HardTimeSync"] = info.HardTimeSync; + result["SntpTimeSync"] = info.SntpTimeSync; + result["CloudTimeSync"] = info.CloudTimeSync; + result["SignalStrength"] = info.SignalStrength; + + // 构造 Detail 部分 + nlohmann::json detail; + detail["Type"] = 1111; // 读取运行状态 + detail["Msg"] = { {"result", result} }; + detail["Code"] = 200; + + // 放到顶层 + j["Detail"] = detail; + + // 打印调试 + std::cout << j.dump(4) << std::endl; + + // ---- 入队发送 ---- + queue_data_t connect_info; + connect_info.strTopic = Topic_Reply_Topic; + connect_info.strText = j.dump(); + connect_info.tag = Topic_Reply_Tag; + connect_info.key = Topic_Reply_Key; + { + std::lock_guard lock(queue_data_list_mutex); + queue_data_list.push_back(std::move(connect_info)); + } + + std::cout << "[send_running_info] queued: " << j.dump() << std::endl; + + // 发送后清除 guid 和标志 + if (dev->isbusy > 0) { + dev->isbusy--; + } + if (dev->isbusy == 0) { + dev->guid.clear(); + dev->busytype = 0; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////版本信息处理 + +void versioninfo_cache_put(const std::string& dev_id, const DeviceVersionInfo& info) +{ + std::lock_guard lk(g_versioninfo_cache_mtx); + g_versioninfo_cache[dev_id] = info; +} + +bool versioninfo_cache_take(const std::string& dev_id, DeviceVersionInfo& out) +{ + std::lock_guard lk(g_versioninfo_cache_mtx); + auto it = g_versioninfo_cache.find(dev_id); + if (it == g_versioninfo_cache.end()) { + return false; + } + + out = std::move(it->second); + g_versioninfo_cache.erase(it); + return true; +} + +bool send_version_info(terminal_dev* dev, const DeviceVersionInfo& info) { + + if (!dev) { + std::cerr << "[send_version_info] dev=nullptr\n"; + return false; + } + + // 判断 isbusy==1 且 busytype==READING_VERSIONINFO + if (dev->isbusy != 1 || dev->busytype != static_cast(DeviceState::READING_VERSIONINFO)) { + std::cerr << "[send_version_info] device not in READING_VERSIONINFO state." << std::endl; + return false; + } + + // 构造 JSON 报文 + nlohmann::json j; + j["guid"] = dev->guid; + j["FrontId"] = FRONT_INST; + j["Node"] = g_front_seg_index; + j["Dev_mac"] = normalize_mac(dev->addr_str); + + // 构造 VersionInfo + nlohmann::json ver; + ver["BaseModel"] = info.BaseModel; + ver["CloudProtocolVer"] = info.CloudProtocolVer; + ver["AppVersion"] = info.AppVersion; + ver["AppDate"] = info.AppDate; + ver["AppChecksum"] = info.AppChecksum; + ver["VoltageWiring"] = info.VoltageWiring; + ver["CurrentBSynthetic"] = info.CurrentBSynthetic; + ver["DataStatInterval"] = info.DataStatInterval; + ver["RatedVoltage"] = info.RatedVoltage; + ver["PTRatio"] = info.PTRatio; + ver["CTRatio"] = info.CTRatio; + ver["SntpIP"] = info.SntpIP; + ver["SntpPort"] = info.SntpPort; + ver["SntpInterval"] = info.SntpInterval; + ver["WebPort"] = info.WebPort; + ver["FtpPort"] = info.FtpPort; + ver["PqdifInterval"] = info.PqdifInterval; + ver["WaveFileTypeCount"] = info.WaveFileTypeCount; + ver["SpecialVersion"] = info.SpecialVersion; + ver["DeviceModel"] = info.DeviceModel; + ver["HarmonicEnergyFlag"] = info.HarmonicEnergyFlag; + ver["PhysicalName"] = info.PhysicalName; + ver["WaveLDName"] = info.WaveLDName; + ver["HighFreqHarmonicFlag"] = info.HighFreqHarmonicFlag; + ver["CommProtocols"] = info.CommProtocols; + ver["TimeSyncMethods"] = info.TimeSyncMethods; + ver["DeviceFunctions"] = info.DeviceFunctions; + + // 构造 Detail 部分 + nlohmann::json detail; + detail["Type"] = 1112; // 读取版本信息 + detail["Msg"] = { {"VersionInfo", ver} }; + detail["Code"] = 200; + + // 放到顶层 + j["Detail"] = detail; + + // 打印调试 + std::cout << j.dump(4) << std::endl; + + // ---- 入队发送 ---- + queue_data_t connect_info; + connect_info.strTopic = Topic_Reply_Topic; + connect_info.strText = j.dump(); + connect_info.tag = Topic_Reply_Tag; + connect_info.key = Topic_Reply_Key; + { + std::lock_guard lock(queue_data_list_mutex); + queue_data_list.push_back(std::move(connect_info)); + } + + std::cout << "[send_version_info] queued: " << j.dump() << std::endl; + + // 发送后清除 guid 和标志 + if (dev->isbusy > 0) { + dev->isbusy--; + } + if (dev->isbusy == 0) { + dev->guid.clear(); + dev->busytype = 0; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////////// void on_device_response_minimal(int response_code, const std::string& id, unsigned char cid, @@ -6115,6 +6356,127 @@ void on_device_response_minimal(int response_code, break; } + // ================= 特殊:读取运行信息 ================= + case DeviceState::READING_RUNNINGINFO: { + std::lock_guard lk(ledgermtx); + + terminal_dev* dev = nullptr; + for (auto& d : terminal_devlist) { + if (d.terminal_id == id) { + dev = &d; + break; + } + } + + if (!dev) { + std::cout << "[RESP][RUNNINGINFO] dev not found, id=" << id + << " rc=" << response_code << std::endl; + break; + } + + RunningInformation info; + const int bt = dev->busytype; + + if (bt == static_cast(DeviceState::READING_RUNNINGINFORMATION_1)) { + if (ok) { + if (runninginfo_cache_take(id, info)) { + + // 发送运行信息 + send_running_info(dev, info); + + } else { + send_reply_to_queue(dev->guid, static_cast(ResponseCode::BAD_REQUEST), + "终端 id: " + dev->terminal_id + "进行业务:" + + get_type_by_state(dev->busytype) + "失败,运行状态缓存不存在"); + + std::cout << "[RESP][RUNNINGINFO][WARN] dev=" << id + << " running info missing in cache" << std::endl; + } + + dev->guid.clear(); + dev->isbusy = 0; + dev->busytype = 0; + dev->busytimecount = 0; + + std::cout << "[RESP][RUNNINGINFO][OK] dev=" << id << std::endl; + } else { + send_reply_to_queue(dev->guid, static_cast(ResponseCode::BAD_REQUEST), + "终端 id: " + dev->terminal_id + "进行业务:" + + get_type_by_state(dev->busytype) + "失败,停止该业务处理"); + + dev->guid.clear(); + dev->isbusy = 0; + dev->busytype = 0; + dev->busytimecount = 0; + + std::cout << "[RESP][RUNNINGINFO][FAIL] dev=" << id + << " rc=" << response_code << std::endl; + } + } + break; + } + + // ================= 特殊:读取版本信息 ================= + + case DeviceState::READING_DEVVERSION: { + std::lock_guard lk(ledgermtx); + + terminal_dev* dev = nullptr; + for (auto& d : terminal_devlist) { + if (d.terminal_id == id) { + dev = &d; + break; + } + } + + if (!dev) { + std::cout << "[RESP][VERSIONINFO] dev not found, id=" << id + << " rc=" << response_code << std::endl; + break; + } + + DeviceVersionInfo info; + const int bt = dev->busytype; + + if (bt == static_cast(DeviceState::READING_DEVVERSION)) { + if (ok) { + if (versioninfo_cache_take(id, info)) { + + // 发送版本信息 + send_version_info(dev, info); + + } else { + send_reply_to_queue(dev->guid, static_cast(ResponseCode::BAD_REQUEST), + "终端 id: " + dev->terminal_id + "进行业务:" + + get_type_by_state(dev->busytype) + "失败,版本信息缓存不存在"); + + std::cout << "[RESP][VERSIONINFO][WARN] dev=" << id + << " version info missing in cache" << std::endl; + } + + dev->guid.clear(); + dev->isbusy = 0; + dev->busytype = 0; + dev->busytimecount = 0; + + std::cout << "[RESP][VERSIONINFO][OK] dev=" << id << std::endl; + } else { + send_reply_to_queue(dev->guid, static_cast(ResponseCode::BAD_REQUEST), + "终端 id: " + dev->terminal_id + "进行业务:" + + get_type_by_state(dev->busytype) + "失败,停止该业务处理"); + + dev->guid.clear(); + dev->isbusy = 0; + dev->busytype = 0; + dev->busytimecount = 0; + + std::cout << "[RESP][VERSIONINFO][FAIL] dev=" << id + << " rc=" << response_code << std::endl; + } + } + break; + } + // ================= 其它状态统一处理 ================= default: { diff --git a/LFtid1056/cloudfront/code/rocketmq.cpp b/LFtid1056/cloudfront/code/rocketmq.cpp index 56b3e7d..afa1ca0 100644 --- a/LFtid1056/cloudfront/code/rocketmq.cpp +++ b/LFtid1056/cloudfront/code/rocketmq.cpp @@ -2349,6 +2349,70 @@ bool parsemsg(const std::string& devid, const std::string& guid, const nlohmann: return true; } + ////////lnk20260312新增读取运行状态、版本、对时、重启 + + case 1111: { // 读取运行状态 + parsed.ok = true; + + std::cout << "[parsemsg] read running status, devid=" << devid + << ", guid=" << guid << std::endl; + + // + if (!recordguid(devid, guid, static_cast(DeviceState::READING_RUNNINGINFORMATION_1), 1)) { + return true; + } + + // + ClientManager::instance().read_runninginformation_action_to_device(devid);//主动触发,读取 + return true; + } + + case 1112: { // 读取版本信息 + parsed.ok = true; + + std::cout << "[parsemsg] read version info, devid=" << devid + << ", guid=" << guid << std::endl; + + if (!recordguid(devid, guid, static_cast(DeviceState::READING_DEVVERSION), 1)) { + return true; + } + + ClientManager::instance().read_devversion_action_to_device(devid); + return true; + } + + case 1113: { // 对时 + parsed.ok = true; + + std::cout << "[parsemsg] time sync, devid=" << devid + << ", guid=" << guid << std::endl; + + if (!recordguid(devid, guid, static_cast(DeviceState::SET_RIGHTTIME_2), 1)) { + return true; + } + + // 方案A:Msg 为空,直接使用当前系统时间下发 + ClientManager::instance().set_righttime_action_to_devic(devid); + + return true; + } + + case 1114: { // 重启 + parsed.ok = true; + + std::cout << "[parsemsg] reboot device, devid=" << devid + << ", guid=" << guid << std::endl; + + if (!recordguid(devid, guid, static_cast(DeviceState::SET_CTRL), 2)) {//分两步,一步校验一步重启 + return true; + } + + ClientManager::instance().set_ctrl_action_to_device(devid,0x01,0x00);//尝试装置重启指令!第一步校验 + return true; + } + + ////////lnk20260312新增读取运行状态、版本、对时、重启 + default: return false; } diff --git a/LFtid1056/dealMsg.cpp b/LFtid1056/dealMsg.cpp index 607967b..a2fb4de 100644 --- a/LFtid1056/dealMsg.cpp +++ b/LFtid1056/dealMsg.cpp @@ -1631,11 +1631,18 @@ void process_received_message(string mac, string id,const char* data, size_t len << ", Cloud=" << result.CloudTimeSync << "\n" << " Signal: " << result.SignalStrength << std::endl; + runninginfo_cache_put(id, result); + + on_device_response_minimal(static_cast(ResponseCode::OK), id, 0, static_cast(DeviceState::READING_RUNNINGINFORMATION_1)); + //读取装置运行信息(主动触发)成功,调整为空闲,处理后续工作。 ClientManager::instance().change_device_state(id, DeviceState::IDLE); } else { // 装置答非所问异常 + + on_device_response_minimal(static_cast(ResponseCode::INTERNAL_ERROR), id, 0, static_cast(DeviceState::READING_RUNNINGINFORMATION_1)); + // 读取装置运行信息(主动触发)失败,调整为空闲状态,处理下一项工作。 ClientManager::instance().change_device_state(id, DeviceState::IDLE); } @@ -2006,11 +2013,15 @@ void process_received_message(string mac, string id,const char* data, size_t len << " Time Sync Methods: 0x" << versionInfo.TimeSyncMethods << "\n" << " Device Functions: 0x" << versionInfo.DeviceFunctions << std::dec << "\n"; + versioninfo_cache_put(id, versionInfo); + on_device_response_minimal(static_cast(ResponseCode::OK), id, 0, static_cast(DeviceState::READING_DEVVERSION)); + //读取装置版本配置信息成功,调整为空闲,处理后续工作。 ClientManager::instance().change_device_state(id, DeviceState::IDLE); } else { // 装置答非所问异常 + on_device_response_minimal(static_cast(ResponseCode::INTERNAL_ERROR), id, 0, static_cast(DeviceState::READING_DEVVERSION)); // 读取装置版本配置信息失败,调整为空闲状态,处理下一项工作。 ClientManager::instance().change_device_state(id, DeviceState::IDLE); }