From cc9d651b5a496066dd84ea7c0e7902f55129c2b4 Mon Sep 17 00:00:00 2001 From: zw <3466561528@qq.com> Date: Wed, 30 Jul 2025 13:52:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=AE=A1=E7=90=86=EF=BC=9A=E6=96=87=E4=BB=B6=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=EF=BC=8C=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LFtid1056/PQSMsg.cpp | 15 ++++ LFtid1056/PQSMsg.h | 21 +++++- LFtid1056/client2.cpp | 61 ++++++++++++++++ LFtid1056/client2.h | 14 +++- LFtid1056/dealMsg.cpp | 163 +++++++++++++++++++++++++++++++++++++++++- 5 files changed, 265 insertions(+), 9 deletions(-) diff --git a/LFtid1056/PQSMsg.cpp b/LFtid1056/PQSMsg.cpp index 35a87a5..cb30432 100644 --- a/LFtid1056/PQSMsg.cpp +++ b/LFtid1056/PQSMsg.cpp @@ -390,4 +390,19 @@ std::vector generate_downloadfile_message(int frameIndex, const s // 调用GetMsg生成完整报文 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_File_Download)); +} + +//文件目录读取报文 传入需要读取的文件路径 +std::vector generate_getfilemenu_message(const std::string& filedir) { + // 创建固定131字节缓冲区 (3 + 128),初始化为0 + std::vector dataBuf(131, 0x00); + + // 复制文件名到缓冲区(偏移量3开始) + size_t copyLen = std::min(filedir.size(), static_cast(128)); + if (copyLen > 0) { + memcpy(dataBuf.data() + 3, filedir.c_str(), copyLen); + } + + // 调用GetMsg生成完整报文 + return GetMsg(dataBuf, static_cast(MsgRequestType::Request_FileDir)); } \ No newline at end of file diff --git a/LFtid1056/PQSMsg.h b/LFtid1056/PQSMsg.h index 889a4ca..9bc59f3 100644 --- a/LFtid1056/PQSMsg.h +++ b/LFtid1056/PQSMsg.h @@ -25,7 +25,9 @@ enum class MsgRequestType : unsigned char { //询问实时数据 Request_New_3S = 0x04, //下载装置文件 - Request_File_Download = 0x07 + Request_File_Download = 0x07, + //询问文件目录 + Request_FileDir = 0x02 }; // 接收报文功能码枚举 enum class MsgResponseType : unsigned char { @@ -40,7 +42,9 @@ enum class MsgResponseType : unsigned char { //主动上送的波形文件信息事件 Response_ActiveSOEInfo = 0x17, //下载装置文件 - Response_File_Download = 0x87 + Response_File_Download = 0x87, + //询问文件目录 + Response_FileDir = 0x82 }; //基础消息结构 class MessageParser { @@ -2048,6 +2052,15 @@ struct 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) + // 生成带协议头的二进制报文 std::vector generate_binary_message( uint16_t msg_type, @@ -2062,4 +2075,6 @@ std::vector generate_statequerystat_message(tagTime time, uint16_ //生成询问实时数据报文 std::vector generate_realstat_message(unsigned char nCpuNo, unsigned char StaTtype, unsigned char flag); //生成文件下载请求报文 当前帧序号+文件名 -std::vector generate_downloadfile_message(int frameIndex, const std::string& fileName); \ No newline at end of file +std::vector generate_downloadfile_message(int frameIndex, const std::string& fileName); +//文件目录读取报文 传入需要读取的文件路径 +std::vector generate_getfilemenu_message(const std::string& filedir); \ No newline at end of file diff --git a/LFtid1056/client2.cpp b/LFtid1056/client2.cpp index 60ca66e..d84d416 100644 --- a/LFtid1056/client2.cpp +++ b/LFtid1056/client2.cpp @@ -992,6 +992,7 @@ bool ClientManager::clear_float_cache(const std::string& identifier) { return false; } +//瀹炴椂鏁版嵁璋冪敤 bool ClientManager::set_real_state_count(const std::string& identifier, int count, ushort point_id) { std::lock_guard lock(mutex_); @@ -1020,6 +1021,66 @@ bool ClientManager::set_real_state_count(const std::string& identifier, int coun return false; } +//璇诲彇鏂囦欢鐩綍璋冪敤 +bool ClientManager::add_file_menu_action_to_device( + const std::string& identifier, + const std::string& file_path) +{ + 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_getfilemenu_message(file_path); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::READING_FILEMENU, packet); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +//鏂囦欢涓嬭浇璋冪敤 +bool ClientManager::add_file_download_action_to_device( + const std::string& identifier, + const std::string& file_path) +{ + 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) + { + // 鐢熸垚涓嬭浇璇锋眰鎶ユ枃 (甯у簭鍙峰浐瀹氫负1锛屼唬琛ㄥ紑濮嬫柊鏂囦欢鐨勪笅杞) + auto downloadMsg = generate_downloadfile_message(1, file_path); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::READING_FILEDATA, downloadMsg); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + 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, std::string& out_scale, diff --git a/LFtid1056/client2.h b/LFtid1056/client2.h index 6fec92c..8047255 100644 --- a/LFtid1056/client2.h +++ b/LFtid1056/client2.h @@ -47,6 +47,8 @@ enum class DeviceState { READING_STATS_TIME, // 读取统计时间 READING_REALSTAT, // 读取实时数据 READING_EVENTFILE, // 暂态波形文件下载 + READING_FILEMENU, // 读取文件目录 + READING_FILEDATA, // 下载文件数据 // 可根据需要添加更多状态 CUSTOM_ACTION // 自定义动作 }; @@ -302,9 +304,6 @@ public: // 清除设备的所有浮点缓存 bool clear_float_cache(const std::string& identifier); - // 新增:设置实时数据收发计数 - bool set_real_state_count(const std::string& identifier, int count, ushort point_id); - // 添加实时数据包到设备缓存 bool add_realtime_packet_to_device(const std::string& identifier, unsigned char packet_type, @@ -362,6 +361,15 @@ public: bool update_current_filename(const std::string& identifier, const std::string& filename); std::string get_current_filename(const std::string& identifier); + + //读取文件目录调用 传入mac/id + 文件路径 + bool add_file_menu_action_to_device(const std::string& identifier, const std::string& file_path); + + // 新增:设置实时数据收发计数 实时数据调用 传入mac/id + 实时次数 + 测点序号 + bool set_real_state_count(const std::string& identifier, int count, ushort point_id); + + //文件下载调用 传入mac/id + 文件位置 + bool add_file_download_action_to_device(const std::string& identifier, const std::string& file_path); private: ClientManager() : loop_(nullptr) {} std::unordered_map> clients_; diff --git a/LFtid1056/dealMsg.cpp b/LFtid1056/dealMsg.cpp index a6685b5..6ecc25e 100644 --- a/LFtid1056/dealMsg.cpp +++ b/LFtid1056/dealMsg.cpp @@ -68,7 +68,9 @@ void process_received_message(string mac, string id,const char* data, size_t len std::cout << "cloud login: " << mac << " state: success!" << std::endl; //装置登录成功 ClientManager::instance().set_cloud_status(id, 1); //设置了云前置登录状态为已登录 - ClientManager::instance().set_real_state_count("D002", 1,1);//登录后测试实时 + //ClientManager::instance().set_real_state_count("D002", 1,1);//登录后测试实时 + //ClientManager::instance().add_file_menu_action_to_device("D002","/etc");//测试文件目录读取 + //ClientManager::instance().add_file_download_action_to_device("D002", "/etc/NPQS570_VX_ZJ_2(V103).icd");//测试文件下载 } if (udata[19] == 0x00) { std::cout << "cloud login: " << mac << " state: fail!" << std::endl; @@ -356,8 +358,21 @@ void process_received_message(string mac, string id,const char* data, size_t len -1, //数据集序号(以数据集方式上送),无填-1 arr //数据数组 ); + //std::cout << js << std::endl; + //// 创建输出流并打开文件(覆盖模式) + //std::ofstream outFile("json.txt"); // 等价于 std::ofstream outFile(filePath, std::ios::out); + + //if (outFile.is_open()) { // 检查文件是否成功打开 + // outFile << js; // 写入字符串 + // outFile.close(); // 关闭文件 + // // 成功提示(实际应用中建议使用日志) + //} + //else { + // // 错误处理:文件打开失败(如路径不存在) + //} + queue_data_t data; data.monitor_no = 1; //暂无意义 data.strTopic = TOPIC_STAT;//统计topic @@ -605,7 +620,14 @@ void process_received_message(string mac, string id,const char* data, size_t len } // 保存文件 - std::string mac_dir = mac; // 使用MAC地址作为目录名 + std::string wavefile = "wave"; // 使用MAC地址作为目录名 + // 创建目录(如果不存在) + if (mkdir(wavefile.c_str(), 0777) != 0 && errno != EEXIST) { + std::cerr << "Failed to create directory: " << wavefile << std::endl; + } + + // 保存文件 + std::string mac_dir = wavefile + "/" + mac; // 使用MAC地址作为目录名 // 创建目录(如果不存在) if (mkdir(mac_dir.c_str(), 0777) != 0 && errno != EEXIST) { std::cerr << "Failed to create directory: " << mac_dir << std::endl; @@ -632,7 +654,142 @@ void process_received_message(string mac, string id,const char* data, size_t len else { // 装置答非所问异常 // 接收波形文件数据错误,调整为空闲状态,处理下一项工作。 - std::cout << "udata[8]: " << static_cast(udata[8]) << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::READING_FILEMENU: + //读取文件目录 + std::cout << "READING_FILEMENU state: Processing stats time from " << mac << std::endl; + if (udata[8] == static_cast(MsgResponseType::Response_FileDir)) { + // 计算结构体大小 + const size_t struct_size = sizeof(tag_dir_info); + const uint8_t* data_ptr = parser.RecvData.data(); + size_t data_size = parser.RecvData.size(); + + std::vector FileList; + + // 遍历接收到的数据 + for (size_t i = 0; i < data_size; i += struct_size) { + if (i + struct_size > data_size) break; + + tag_dir_info dir_info; + memcpy(&dir_info, data_ptr + i, struct_size); + + // 字节序转换 (大端 -> 小端) + dir_info.flag = ntohl(dir_info.flag); + dir_info.size = ntohl(dir_info.size); + + std::string gbk_name(dir_info.name, strnlen(dir_info.name, sizeof(dir_info.name))); + + // 打印文件名 + std::cout << "file name:" << gbk_name << std::endl; + + // 添加到文件列表 + FileList.push_back(dir_info); + } + + // 这里可以添加发送文件列表的逻辑 + // 例如: send_file_list(FileList); + + // 处理完成后重置状态 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 接收目录数据错误,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::READING_FILEDATA: + //下载文件数据 和暂态文件下载共用同一功能码 + std::cout << "READING_FILEDATA state: Processing stats time from " << mac << std::endl; + if (udata[8] == static_cast(MsgResponseType::Response_File_Download)) + { + // 提取当前帧序号(12-15字节,大端序) + int current_frame = (static_cast(udata[12]) << 24) | + (static_cast(udata[13]) << 16) | + (static_cast(udata[14]) << 8) | + static_cast(udata[15]); + + // 提取总帧数(16-19字节,大端序) + int total_frames = (static_cast(udata[16]) << 24) | + (static_cast(udata[17]) << 16) | + (static_cast(udata[18]) << 8) | + static_cast(udata[19]); + + //提取数据 + const uint8_t* data_ptr = parser.RecvData.data() + 14; + size_t data_size = parser.RecvData.size() - 14; + + // 如果是第一帧,记录文件名 + if (current_frame == 1) { + ClientManager::DownloadInfo info; + if (ClientManager::instance().parse_download_packet(id, info)) { + ClientManager::instance().update_current_filename(id, info.filename); + } + } + // 获取文件名 + std::string filename = ClientManager::instance().get_current_filename(id); + // 添加到缓存 + ClientManager::instance().add_file_packet_to_device(id, current_frame, data_ptr, data_size); + + //判断是否收全,未收全则继续发送报文,收全则取出所有缓存组装文件并保存至本地,推送消息 + if (current_frame < total_frames) { + // 未收全,更新帧序号并保持状态,等待后续自动发送已修改的新报文 + int nextframe = current_frame + 1; + auto downloadMsg = generate_downloadfile_message(nextframe, filename); + ClientManager::instance().change_device_state(id, DeviceState::READING_FILEDATA, downloadMsg); + } + else { + // 已收全,在此处处理文件 + std::cout << "mac: " << mac << " fileinfo: " << filename << std::endl; + // 获取缓存中的所有分片 + auto packets = ClientManager::instance().get_and_clear_file_packets(id); + + // 合并文件内容 + std::vector file_data; + for (const auto& packet : packets) { + file_data.insert(file_data.end(), packet.begin(), packet.end()); + } + + // 保存文件 + std::string wavefile = "download"; // 使用MAC地址作为目录名 + // 创建目录(如果不存在) + if (mkdir(wavefile.c_str(), 0777) != 0 && errno != EEXIST) { + std::cerr << "Failed to create directory: " << wavefile << std::endl; + } + + // 保存文件 + std::string mac_dir = wavefile + "/" + mac; // 使用MAC地址作为目录名 + // 创建目录(如果不存在) + if (mkdir(mac_dir.c_str(), 0777) != 0 && errno != EEXIST) { + std::cerr << "Failed to create directory: " << mac_dir << std::endl; + } + + std::string path = extract_filename(filename); + + std::string file_path = mac_dir + "/" + path; + std::ofstream out_file(file_path, std::ios::binary); + if (out_file) { + out_file.write(reinterpret_cast(file_data.data()), + file_data.size()); + std::cout << "File saved: " << file_path << std::endl; + } + else { + std::cerr << "Failed to save file: " << file_path + << ", Error: " << strerror(errno) << std::endl; + } + + //当前文件下载完毕,调整为空闲处理下一项工作(如果这里后续有新文件等待下载,一般已经存入等待队列等候处理了,调成空闲状态后直接就会开始新文件的下载工作) + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + + } + else { + // 装置答非所问异常 + // 下载文件数据错误,调整为空闲状态,处理下一项工作。 ClientManager::instance().change_device_state(id, DeviceState::IDLE); } break;