From dfe0f2e5e234b7c8f4d7145976d6c64bf168377e Mon Sep 17 00:00:00 2001 From: zhangwen <3466561528@qq.com> Date: Tue, 31 Mar 2026 09:44:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=96=87=E4=BB=B6=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0=20=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E5=88=9B=E5=BB=BA=20=E7=9B=AE=E5=BD=95=E5=88=A0?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LFtid1056/PQSMsg.cpp | 128 ++++++++++++++- LFtid1056/PQSMsg.h | 44 ++++++ LFtid1056/client2.cpp | 351 +++++++++++++++++++++++++++++++++++++++++- LFtid1056/client2.h | 99 ++++++++++++ LFtid1056/dealMsg.cpp | 132 +++++++++++++++- 5 files changed, 750 insertions(+), 4 deletions(-) diff --git a/LFtid1056/PQSMsg.cpp b/LFtid1056/PQSMsg.cpp index 412e621..8173a46 100644 --- a/LFtid1056/PQSMsg.cpp +++ b/LFtid1056/PQSMsg.cpp @@ -487,6 +487,133 @@ std::vector generate_getfilemenu_message(const std::string& filed return GetMsg(dataBuf, static_cast(MsgRequestType::Request_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) { + + // 创建 17+128 字节头部 + 数据区缓冲区,初始化为0 + std::vector DataBuf(17 + 128 + data.size(), 0x00); + // 拷贝数据体到17+128字节头部之后 + std::copy(data.begin(), data.end(), DataBuf.begin() + 17 + 128); + + DataBuf[0] = 0x00; // 备用 + DataBuf[1] = 0x00; // 备用 + DataBuf[2] = 0x00; // 备用 + + // 4字节当前帧序号 + DataBuf[3] = static_cast(((sendCount + 1) >> 24) & 0xFF); + DataBuf[4] = static_cast(((sendCount + 1) >> 16) & 0xFF); + DataBuf[5] = static_cast(((sendCount + 1) >> 8) & 0xFF); + DataBuf[6] = static_cast((sendCount + 1) & 0xFF); + + // 4字节总帧数 + DataBuf[7] = static_cast((count >> 24) & 0xFF); + DataBuf[8] = static_cast((count >> 16) & 0xFF); + DataBuf[9] = static_cast((count >> 8) & 0xFF); + DataBuf[10] = static_cast(count & 0xFF); + + // 4字节总大小 + DataBuf[11] = static_cast((fileSize >> 24) & 0xFF); + DataBuf[12] = static_cast((fileSize >> 16) & 0xFF); + DataBuf[13] = static_cast((fileSize >> 8) & 0xFF); + DataBuf[14] = static_cast(fileSize & 0xFF); + + // 2字节校验码 + DataBuf[15] = static_cast((crc >> 8) & 0xFF); + DataBuf[16] = static_cast(crc & 0xFF); + + // 复制文件名到缓冲区(偏移量17开始) + size_t copyLen = std::min(filedir.size(), static_cast(128)); + if (copyLen > 0) { + memcpy(DataBuf.data() + 17, filedir.c_str(), copyLen); + } + + // 调用通用报文生成函数,功能码8对应上送文件 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_File_Send)); +} + +/** + * @brief 文件删除报文 + * @param filedir 删除文件全路径 + * @return 包含完整报文的字节向量 + */ +std::vector generate_deletefile_message(const std::string& filedir) { + // 创建 3 字节头部 + 数据区缓冲区,初始化为0 + std::vector DataBuf(3 + 128, 0x00); + + DataBuf[0] = 0x00; // 备用 + DataBuf[1] = 0x00; // 备用 + DataBuf[2] = 0x00; // 备用 + + // 复制文件名到缓冲区(偏移量3开始) + size_t copyLen = std::min(filedir.size(), static_cast(128)); + if (copyLen > 0) { + memcpy(DataBuf.data() + 3, filedir.c_str(), copyLen); + } + + // 调用通用报文生成函数,功能码9对应删除文件 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_File_Del)); +} + +/** + * @brief 文件目录创建报文 + * @param filedir 目录全路径 + * @return 包含完整报文的字节向量 + */ +std::vector generate_setmenu_message(const std::string& filedir) { + // 创建 3 字节头部 + 数据区缓冲区,初始化为0 + std::vector DataBuf(3 + 128, 0x00); + + DataBuf[0] = 0x00; // 备用 + DataBuf[1] = 0x00; // 备用 + DataBuf[2] = 0x00; // 备用 + + // 复制文件名到缓冲区(偏移量3开始) + size_t copyLen = std::min(filedir.size(), static_cast(128)); + if (copyLen > 0) { + memcpy(DataBuf.data() + 3, filedir.c_str(), copyLen); + } + + // 调用通用报文生成函数,功能码11对应创建目录 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Menu_Set)); +} + +/** + * @brief 文件目录删除报文 + * @param filedir 目录全路径 + * @return 包含完整报文的字节向量 + */ +std::vector generate_delmenu_message(const std::string& filedir) { + // 创建 3 字节头部 + 数据区缓冲区,初始化为0 + std::vector DataBuf(3 + 128, 0x00); + + DataBuf[0] = 0x00; // 备用 + DataBuf[1] = 0x00; // 备用 + DataBuf[2] = 0x00; // 备用 + + // 复制文件名到缓冲区(偏移量3开始) + size_t copyLen = std::min(filedir.size(), static_cast(128)); + if (copyLen > 0) { + memcpy(DataBuf.data() + 3, filedir.c_str(), copyLen); + } + + // 调用通用报文生成函数,功能码12对应删除目录 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Menu_Del)); +} + // 请求定值报文 传入测点号 std::vector generate_requestFixValue_message(unsigned char nCpuNo) { // 参数检查 @@ -886,4 +1013,3 @@ std::vector generate_control_message(uint8_t type, uint8_t ctrlfl return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Ctrl)); } - diff --git a/LFtid1056/PQSMsg.h b/LFtid1056/PQSMsg.h index 7534e16..b459a79 100644 --- a/LFtid1056/PQSMsg.h +++ b/LFtid1056/PQSMsg.h @@ -28,6 +28,14 @@ enum class MsgRequestType : unsigned char { 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, //询问装置定值 @@ -69,6 +77,8 @@ enum class MsgResponseType : unsigned char { Response_ActiveSOEInfo = 0x17, //下载装置文件 Response_File_Download = 0x87, + //上传装置文件 帧传递采用默认应答,最后一帧回复后,装置再应答一帧收全 + Response_File_Send = 0x88, //询问文件目录 Response_FileDir = 0x82, //询问装置定值 @@ -2381,6 +2391,40 @@ std::vector generate_realstat_message(unsigned char nCpuNo, unsig 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); // 请求定值描述报文 diff --git a/LFtid1056/client2.cpp b/LFtid1056/client2.cpp index 3bb111a..66485ab 100644 --- a/LFtid1056/client2.cpp +++ b/LFtid1056/client2.cpp @@ -64,6 +64,30 @@ static uint32_t CalcNormalCrc32_Char(const std::vector& bytes, return crc; } +// 涓 C# Crc_16_new 瀹屽叏瀵瑰簲锛圡odbus CRC16锛 +static uint16_t CalcCrc16_Char(const std::vector& bytes) +{ + uint16_t crc = 0xFFFF; + + for (size_t i = 0; i < bytes.size(); ++i) + { + crc = static_cast(crc ^ static_cast(bytes[i])); + for (int j = 0; j < 8; ++j) + { + if ((crc & 0x0001) == 0x0001) + { + crc = static_cast((crc >> 1) ^ 0xA001); + } + else + { + crc = static_cast(crc >> 1); + } + } + } + + return crc; +} + // ClientContext 瀹炵幇 ClientContext::ClientContext(uv_loop_t* loop, const DeviceInfo& device, int index) : loop(loop), state(ConnectionState::DISCONNECTED), @@ -523,6 +547,120 @@ bool ClientContext::has_active_upgrade_task() const return upgrade_task_.active; } +/** + * @brief 鏂囦欢涓婇佸弬鏁板垵濮嬪寲 + * @param file 涓婇佹枃浠跺唴瀹 + * @param frame_payload_size 鍗曞抚鏁版嵁闀 + * @param dest_file_path 瑁呯疆绔洰鏍囧叏璺緞 + * @return 鏄惁鍒濆鍖栨垚鍔 + */ +bool ClientContext::prepare_send_file_task(const std::vector& file, + uint32_t frame_payload_size, + const std::string& dest_file_path) +{ + if (file.empty() || frame_payload_size == 0 || dest_file_path.empty()) { + return false; + } + + std::lock_guard lock(send_file_mutex_); + + send_file_task_.file_data = file; + send_file_task_.file_size = static_cast(file.size()); + send_file_task_.file_crc = CalcCrc16_Char(file); + send_file_task_.frame_payload_size = frame_payload_size; + send_file_task_.total_frames = + static_cast((file.size() + frame_payload_size - 1) / frame_payload_size); + send_file_task_.next_frame_index = 0; + send_file_task_.dest_file_path = dest_file_path; + send_file_task_.active = (send_file_task_.total_frames > 0); + + return send_file_task_.active; +} + +/** + * @brief 鐢熸垚鏂囦欢涓婇佺殑涓嬩竴甯ф姤鏂 + * @param out_packet 涓婇佹姤鏂 + * @param finished 鏄惁缁撴潫 + * @return 鏄惁缁х画 + */ +bool ClientContext::build_next_send_file_packet(std::vector& out_packet, bool& finished) +{ + std::lock_guard lock(send_file_mutex_); + + finished = false; + out_packet.clear(); + + if (!send_file_task_.active) { + return false; + } + + if (send_file_task_.next_frame_index >= send_file_task_.total_frames) { + finished = true; + send_file_task_.active = false; + return false; + } + + std::vector frame_data = + slice_frame_data(send_file_task_.file_data, + send_file_task_.next_frame_index, + send_file_task_.frame_payload_size); + + if (frame_data.empty()) { + send_file_task_.active = false; + return false; + } + + out_packet = generate_sendfile_message( + frame_data, + send_file_task_.next_frame_index, // 0-based锛屽嚱鏁板唴閮ㄤ細 +1 + send_file_task_.total_frames, + send_file_task_.file_size, + send_file_task_.file_crc, + send_file_task_.dest_file_path + ); + + ++send_file_task_.next_frame_index; + + if (send_file_task_.next_frame_index >= send_file_task_.total_frames) { + finished = true; + } + + return true; +} + +/** + * @brief 鑾峰彇褰撳墠鏂囦欢涓婇佺殑褰撳墠甯у拰鎬诲抚鏁 + * @param current_frame_index 褰撳墠甯 + * @param total_frames 鎬诲抚鏁 + * @return 鏄惁姝e父 + */ +bool ClientContext::get_send_file_progress(uint32_t& current_frame_index, uint32_t& total_frames) const +{ + std::lock_guard lock(send_file_mutex_); + + if (!send_file_task_.active) { + current_frame_index = 0; + total_frames = 0; + return false; + } + + current_frame_index = send_file_task_.next_frame_index; + total_frames = send_file_task_.total_frames; + return true; +} + +void ClientContext::clear_send_file_task() +{ + std::lock_guard lock(send_file_mutex_); + send_file_task_ = SendFileTask{}; +} + +bool ClientContext::has_active_send_file_task() const +{ + std::lock_guard lock(send_file_mutex_); + return send_file_task_.active; +} + // 鐗堟湰姣旇緝鍑芥暟鐨勮緟鍔╁嚱鏁帮細鍒嗗壊瀛楃涓插苟杞崲涓烘暣鏁板悜閲 std::vector splitVersionString(const std::string& versionStr) { std::vector segments; @@ -1653,6 +1791,108 @@ bool ClientManager::add_file_download_action_to_device( return false; // 璁惧鏈壘鍒 } +/** + * @brief 鐢熸垚鍒犻櫎瑁呯疆鏂囦欢鎶ユ枃 + * @param file_path 鏂囦欢鍏ㄨ矾寰 + * @return 鍙戦佺粨鏋 + */ +bool ClientManager::add_file_delete_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 delMsg = generate_deletefile_message(file_path); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 鍒犻櫎鎸囧畾鏂囦欢) + ctx->add_action(DeviceState::DEL_FILE, delMsg); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +/** + * @brief 鐢熸垚鍒涘缓鐩綍鎶ユ枃 + * @param file_path 鏂囦欢鍏ㄨ矾寰 + * @return 鍙戦佺粨鏋 + */ +bool ClientManager::add_menu_set_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 delMsg = generate_setmenu_message(file_path); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 鍒涘缓鐩綍) + ctx->add_action(DeviceState::SEND_MENU, delMsg); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +/** + * @brief 鐢熸垚鍒犻櫎鐩綍鎶ユ枃 + * @param file_path 鏂囦欢鍏ㄨ矾寰 + * @return 鍙戦佺粨鏋 + */ +bool ClientManager::add_menu_del_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 delMsg = generate_delmenu_message(file_path); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 鍒犻櫎鐩綍) + ctx->add_action(DeviceState::DEL_MENU, delMsg); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + //鑾峰彇鎸囧畾瑁呯疆鎸囧畾娴嬬偣涓嬬殑瀹氬兼暟鎹 bool ClientManager::get_fixedvalue_action_to_device(const std::string& identifier, ushort point_id) { std::lock_guard lock(mutex_); @@ -1908,7 +2148,7 @@ bool ClientManager::read_devversion_action_to_device(const std::string& identifi /** * @brief 鐢熸垚棰勫崌绾ф牎楠屾姤鏂 * @param path 棰勬牎楠屾枃浠惰矾寰 - * @return 鍖呭惈瀹屾暣鎶ユ枃鐨勫瓧鑺傚悜閲 + * @return 鍙戦佺粨鏋 */ bool ClientManager::set_preupgrade_action_to_device(const std::string& identifier, const std::string& path) { std::lock_guard lock(mutex_); @@ -2043,6 +2283,115 @@ bool ClientManager::try_get_next_upgrade_packet_to_device(const std::string& ide return false; // 鏈壘鍒拌澶 } +/** + * @brief 鏂囦欢涓婇佸姩浣 鍙戦佸垵濮嬪抚 + * @param file 涓婇佹枃浠跺唴瀹 + * @param sin_length 涓婇佸崟甯ч暱搴 + * @param dest_file_path 瑁呯疆绔洰鏍囧叏璺緞 + * @return 鍙戦佺粨鏋 + */ +bool ClientManager::send_file_action_to_device(const std::string& identifier, + const std::vector& file, + int sin_length, + const std::string& dest_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. 鍏堝噯澶囨枃浠朵笂閫佷换鍔 + if (!ctx->prepare_send_file_task(file, + static_cast(sin_length), + dest_file_path)) { + return false; + } + + // 2. 鐢熸垚棣栧抚涓婇佹姤鏂 + std::vector first_packet; + bool finished = false; + if (!ctx->build_next_send_file_packet(first_packet, finished) || + first_packet.empty()) { + ctx->clear_send_file_task(); + return false; + } + + // 3. 娣诲姞鍔ㄤ綔鍒伴槦鍒 + ctx->add_action(DeviceState::SEND_FILE, first_packet); + + // 4. 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; + } + } + + return false; +} + +/** + * @brief 鏂囦欢涓婇佸姩浣 鏌ヨ骞剁敓鎴愪笅涓甯ф姤鏂 + * @param identifier 瑁呯疆鏍囪瘑锛坉evice_id 鎴 mac锛 + * @param current_frame_index 鑾峰彇褰撳墠甯(0-based锛岃〃绀轰笅涓娆¤鍙戦佺殑甯у彿) + * @param total_frames 鑾峰彇鎬诲抚鏁 + * @param all_sent 鏄惁鍏ㄩ儴鍙戦佸畬姣 + * @param packet 杈撳嚭鐨勪笅涓甯ф姤鏂囷紱鑻ュ凡鍙戦佸畬姣曞垯涓虹┖ + * @return 鑾峰彇缁撴灉 + */ +bool ClientManager::try_get_next_send_file_packet_to_device(const std::string& identifier, + uint32_t& current_frame_index, + uint32_t& total_frames, + bool& all_sent, + std::vector& packet) +{ + current_frame_index = 0; + total_frames = 0; + all_sent = false; + packet.clear(); + + 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) + { + // 鍏堣幏鍙栧綋鍓嶈繘搴 + if (!ctx->get_send_file_progress(current_frame_index, total_frames)) { + return false; // 娌℃湁娲诲姩涓婇佷换鍔 + } + + // 宸茬粡鍙戝畬 + if (current_frame_index >= total_frames) { + all_sent = true; + return true; + } + + // 鐢熸垚涓嬩竴甯ф姤鏂 + bool finished = false; + if (!ctx->build_next_send_file_packet(packet, finished)) { + packet.clear(); + return false; + } + + // build_next_send_file_packet 涔嬪悗锛宯ext_frame_index 宸茶嚜澧 + ctx->get_send_file_progress(current_frame_index, total_frames); + + if (current_frame_index >= total_frames) { + all_sent = true; + } + + return true; + } + } + + return false; +} + /** * @brief 鐢熸垚瑁呯疆鎺у埗鍛戒护鎶ユ枃 * @param type 鍛戒护绫诲瀷 1-瑁呯疆澶嶄綅锛2-鍚姩褰曟尝锛3-鍚姩200ms鏁版嵁璁板綍锛4-鍚姩3绉掓暟鎹褰 diff --git a/LFtid1056/client2.h b/LFtid1056/client2.h index 1f6145a..8a8bf5c 100644 --- a/LFtid1056/client2.h +++ b/LFtid1056/client2.h @@ -50,6 +50,10 @@ enum class DeviceState { READING_REALSTAT, // 读取实时数据 READING_EVENTFILE, // 暂态波形文件下载 READING_FILEMENU, // 读取文件目录 + SEND_FILE, // 文件上送 + DEL_FILE, // 文件删除 + SEND_MENU, // 目录创建 + DEL_MENU, // 目录删除 READING_FILEDATA, // 下载文件数据 READING_FIXEDVALUE, // 读取测点定值 READING_FIXEDVALUEDES, // 读取测点定值描述 @@ -185,6 +189,53 @@ public: bool get_upgrade_progress(uint32_t& current_frame_index, uint32_t& total_frames) const; //升级任务管理-------------------------------------------------- + // 文件上送任务管理-------------------------------------------------- + struct SendFileTask + { + std::vector file_data; // 完整上送文件 + uint32_t file_size = 0; // 文件总大小 + uint16_t file_crc = 0; // 文件CRC16 + uint32_t frame_payload_size = 0; // 单帧数据长度 + uint32_t total_frames = 0; // 总帧数 + uint32_t next_frame_index = 0; // 下一个要发送的帧序号(0-based) + std::string dest_file_path; // 装置端目标全路径 + bool active = false; // 当前是否存在上送任务 + }; + + mutable std::mutex send_file_mutex_; + SendFileTask send_file_task_; + + /** + * @brief 文件上送参数初始化 + * @param file 上送文件内容 + * @param frame_payload_size 单帧数据长 + * @param dest_file_path 装置端目标全路径 + * @return 是否初始化成功 + */ + bool prepare_send_file_task(const std::vector& file, + uint32_t frame_payload_size, + const std::string& dest_file_path); + + /** + * @brief 生成文件上送的下一帧报文 + * @param out_packet 上送报文 + * @param finished 是否结束 + * @return 是否继续 + */ + bool build_next_send_file_packet(std::vector& out_packet, bool& finished); + + void clear_send_file_task(); + bool has_active_send_file_task() const; + + /** + * @brief 获取当前文件上送的当前帧和总帧数 + * @param current_frame_index 当前帧 + * @param total_frames 总帧数 + * @return 是否正常 + */ + bool get_send_file_progress(uint32_t& current_frame_index, uint32_t& total_frames) const; + // 文件上送任务管理-------------------------------------------------- + // 统计数据缓存 struct PointFloatCache { std::array data; // 存储四种数据类型(0-3) @@ -477,6 +528,27 @@ public: //文件下载调用 传入mac/id + 文件位置 bool add_file_download_action_to_device(const std::string& identifier, const std::string& file_path); + /** + * @brief 生成删除装置文件报文 + * @param file_path 文件全路径 + * @return 发送结果 + */ + bool add_file_delete_action_to_device(const std::string& identifier, const std::string& file_path); + + /** + * @brief 生成创建目录报文 + * @param file_path 文件全路径 + * @return 发送结果 + */ + bool add_menu_set_action_to_device(const std::string& identifier, const std::string& file_path); + + /** + * @brief 生成删除目录报文 + * @param file_path 文件全路径 + * @return 发送结果 + */ + bool add_menu_del_action_to_device(const std::string& identifier, const std::string& file_path); + //获取指定装置指定测点下的定值数据 传入mac/id + 测点序号 bool get_fixedvalue_action_to_device(const std::string& identifier, ushort point_id); @@ -532,6 +604,33 @@ public: bool& all_sent, std::vector& packet); + /** + * @brief 文件上送动作 发送初始帧 + * @param file 上送文件内容 + * @param sin_length 上送单帧长度 + * @param dest_file_path 装置端目标全路径 + * @return 发送结果 + */ + bool send_file_action_to_device(const std::string& identifier, + const std::vector& file, + int sin_length, + const std::string& dest_file_path); + + /** + * @brief 文件上送动作 查询并生成下一帧报文 + * @param identifier 装置标识(device_id 或 mac) + * @param current_frame_index 获取当前帧(0-based,表示下一次要发送的帧号) + * @param total_frames 获取总帧数 + * @param all_sent 是否全部发送完毕 + * @param packet 输出的下一帧报文;若已发送完毕则为空 + * @return 获取结果 + */ + bool try_get_next_send_file_packet_to_device(const std::string& identifier, + uint32_t& current_frame_index, + uint32_t& total_frames, + bool& all_sent, + std::vector& packet); + //设备运行情况判断 bool get_dev_status(const std::string& identifier); /** diff --git a/LFtid1056/dealMsg.cpp b/LFtid1056/dealMsg.cpp index dade921..4ed447f 100644 --- a/LFtid1056/dealMsg.cpp +++ b/LFtid1056/dealMsg.cpp @@ -176,14 +176,24 @@ void process_received_message(string mac, string id,const char* data, size_t len ClientManager::instance().read_devversion_action_to_device(id);//涓诲姩瑙﹀彂锛岃鍙栬缃増鏈厤缃俊鎭紝浠呭湪瑁呯疆鐧诲綍鍚庢墽琛屼竴娆★紝褰撳墠鑾峰彇鐗堟湰淇℃伅纭瀵规椂鎶ユ枃缁撴瀯銆 //std::vector file_data = read_file_as_bytes("pqs_arm2.bin"); - //ClientManager::instance().send_upgrade_action_to_device(id, file_data,10240);//榛樿鍗曞抚鏈澶10240 + //ClientManager::instance().send_file_action_to_device(id, file_data,10240,"/etc/test1.bin");//榛樿鍗曞抚鏈澶10240 鏂囦欢涓婇佹祦绋 + + //std::vector file_data = read_file_as_bytes("pqs_arm2.bin"); + //ClientManager::instance().send_upgrade_action_to_device(id, file_data,10240);//榛樿鍗曞抚鏈澶10240 绋嬪簭鍗囩骇娴佺▼ //ClientManager::instance().set_preupgrade_action_to_device(id, "");//瑁呯疆鍗囩骇棰勬牎楠屾祦绋 鏍¢獙鏂囦欢鑷姩鐢熸垚 褰撳墠濉┖ //ClientManager::instance().set_ctrl_action_to_device(id,0x01,0x00);//灏濊瘯瑁呯疆閲嶅惎鎸囦护锛 + //ClientManager::instance().add_menu_set_action_to_device(id,"/etc/tt1");//鍒涘缓鐩綍 + //ClientManager::instance().add_file_menu_action_to_device(id, "/etc"); + //ClientManager::instance().add_menu_del_action_to_device(id, "/etc/tt1");//鍒犻櫎鐩綍 + //ClientManager::instance().add_file_menu_action_to_device(id, "/etc"); + + //ClientManager::instance().add_file_menu_action_to_device(id,"/etc");//娴嬭瘯鏂囦欢鐩綍璇诲彇 + //ClientManager::instance().add_file_delete_action_to_device(id, "/etc/test1.bin");//鏂囦欢鍒犻櫎鍔熻兘 //ClientManager::instance().get_dev_status(id);//璁惧鍦ㄧ嚎鎯呭喌鍒ゆ柇 ture鍦ㄧ嚎 false绂荤嚎 //ClientManager::instance().set_real_state_count("D002", 1,1);//鐧诲綍鍚庢祴璇曞疄鏃 - //ClientManager::instance().add_file_menu_action_to_device(id,"/etc");//娴嬭瘯鏂囦欢鐩綍璇诲彇 + //ClientManager::instance().add_file_download_action_to_device("D002", "/etc/NPQS570_VX_ZJ_2(V103).icd");//娴嬭瘯鏂囦欢涓嬭浇 //ClientManager::instance().get_fixedvalue_action_to_device(id,1);//娴嬭瘯鑾峰彇瑁呯疆娴嬬偣瀹氬兼暟鎹 //ClientManager::instance().get_fixedvaluedes_action_to_device(id);//娴嬭瘯鑾峰彇瑁呯疆瀹氬兼弿杩 @@ -903,6 +913,124 @@ void process_received_message(string mac, string id,const char* data, size_t len } break; + case DeviceState::SEND_FILE: + //鏂囦欢涓婇 + if(udata[8] == static_cast(MsgResponseType::Response_File_Send)){ + //鏂囦欢搴旂瓟鏈鍚庝竴甯у悗锛屽啀鍥炲鐨勭粨鏉熷抚 + std::cout << "*** send file success ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else if (udata[8] == static_cast(MsgResponseType::Response_NewACK)) { + uint32_t current_frame_index = 0; // 褰撳墠甯(涓嬩竴娆¤鍙戠殑甯у彿锛0-based) + uint32_t total_frames = 0; // 鎬诲抚鏁 + bool all_sent = false; // 鏄惁鎵鏈夊抚閮藉凡鍙戝嚭 + std::vector packet; // 涓嬩竴甯ф姤鏂 + + bool ok = ClientManager::instance().try_get_next_send_file_packet_to_device( + id, + current_frame_index, + total_frames, + all_sent, + packet + ); + + if (!ok) { + // 缁勮鍚庣画鏂囦欢涓婇佹姤鏂囧け璐 + std::cout << "*** send file get next packet fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else if (!packet.empty()) { + // 鎴愬姛鎷垮埌涓嬩竴甯э紝绔嬪嵆鍙戦 + std::cout << "宸茬敓鎴愬苟鍙戦佷笅涓甯ф枃浠朵笂閫佹姤鏂囷紝褰撳墠杩涘害: " + << current_frame_index << "/" << total_frames << std::endl; + + // 鍜屽崌绾т竴鏍凤紝鐩存帴鍒囩姸鎬佸彂閫侊紝閬垮厤琚叾浠栧姩浣滄墦鏂 + ClientManager::instance().change_device_state(id, DeviceState::SEND_FILE, packet); + + if (all_sent) { + std::cout << "鏈鍚庝竴甯у凡鍙戝嚭锛岀瓑寰呰缃渶缁堟枃浠跺簲绛擻n"; + } + } + else if (all_sent) { + // 鎵鏈夋暟鎹抚閮藉凡缁忓彂閫佸畬姣曪紝姝ゆ椂绛夊緟 Response_File_Send 鏈缁堝簲绛 + std::cout << "鎵鏈夋枃浠跺抚閮藉凡鍙戦佸畬姣曪紝绛夊緟瑁呯疆鏈缁堟枃浠跺簲绛擻n"; + return; + } + else { + // 鐞嗚涓婁笉搴斿嚭鐜 + std::cout << "*** send file invalid next packet ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + } + else if (udata[8] == static_cast(MsgResponseType::Response_NewNACK)) { + // 褰撳墠甯ц鎷掓敹锛屾枃浠朵笂閫佸け璐 + std::cout << "*** send file 0x41 fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 瑁呯疆绛旈潪鎵闂 + std::cout << "*** send file ?? fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::DEL_FILE: + //鏂囦欢鍒犻櫎 + if (udata[8] == static_cast(MsgResponseType::Response_NewACK)) { + //鏂囦欢鍒犻櫎瀹屾瘯锛 + std::cout << "*** del file success ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else if (udata[8] == static_cast(MsgResponseType::Response_NewNACK)) { + // 褰撳墠甯ц鎷掓敹锛屾枃浠跺垹闄ゅけ璐 + std::cout << "*** del file 0x41 fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 瑁呯疆绛旈潪鎵闂 + std::cout << "*** del file ?? fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::SEND_MENU: + //鍒涘缓鐩綍 + if (udata[8] == static_cast(MsgResponseType::Response_NewACK)) { + //鍒涘缓鐩綍瀹屾瘯锛 + std::cout << "*** send menu success ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else if (udata[8] == static_cast(MsgResponseType::Response_NewNACK)) { + // 褰撳墠甯ц鎷掓敹锛屽垱寤虹洰褰曞け璐 + std::cout << "*** send menu 0x41 fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 瑁呯疆绛旈潪鎵闂 + std::cout << "*** send menu ?? fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::DEL_MENU: + //鍒犻櫎鐩綍 + if (udata[8] == static_cast(MsgResponseType::Response_NewACK)) { + //鍒犻櫎鐩綍瀹屾瘯锛 + std::cout << "*** del menu success ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else if (udata[8] == static_cast(MsgResponseType::Response_NewNACK)) { + // 褰撳墠甯ц鎷掓敹锛屽垹闄ょ洰褰曞け璐 + std::cout << "*** del menu 0x41 fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 瑁呯疆绛旈潪鎵闂 + std::cout << "*** del menu ?? fail ***! " << mac << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + case DeviceState::READING_FILEDATA: //涓嬭浇鏂囦欢鏁版嵁 鍜屾殏鎬佹枃浠朵笅杞藉叡鐢ㄥ悓涓鍔熻兘鐮 if (udata[8] == static_cast(MsgResponseType::Response_File_Download))