新增文件删除 文件上传 目录创建 目录删除
This commit is contained in:
@@ -64,6 +64,30 @@ static uint32_t CalcNormalCrc32_Char(const std::vector<unsigned char>& bytes,
|
||||
return crc;
|
||||
}
|
||||
|
||||
// 与 C# Crc_16_new 完全对应(Modbus CRC16)
|
||||
static uint16_t CalcCrc16_Char(const std::vector<unsigned char>& bytes)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
|
||||
for (size_t i = 0; i < bytes.size(); ++i)
|
||||
{
|
||||
crc = static_cast<uint16_t>(crc ^ static_cast<uint16_t>(bytes[i]));
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
if ((crc & 0x0001) == 0x0001)
|
||||
{
|
||||
crc = static_cast<uint16_t>((crc >> 1) ^ 0xA001);
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = static_cast<uint16_t>(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<unsigned char>& 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<std::mutex> lock(send_file_mutex_);
|
||||
|
||||
send_file_task_.file_data = file;
|
||||
send_file_task_.file_size = static_cast<uint32_t>(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<uint32_t>((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<unsigned char>& out_packet, bool& finished)
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<unsigned char> 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 是否正常
|
||||
*/
|
||||
bool ClientContext::get_send_file_progress(uint32_t& current_frame_index, uint32_t& total_frames) const
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<std::mutex> lock(send_file_mutex_);
|
||||
send_file_task_ = SendFileTask{};
|
||||
}
|
||||
|
||||
bool ClientContext::has_active_send_file_task() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(send_file_mutex_);
|
||||
return send_file_task_.active;
|
||||
}
|
||||
|
||||
// 版本比较函数的辅助函数:分割字符串并转换为整数向量
|
||||
std::vector<int> splitVersionString(const std::string& versionStr) {
|
||||
std::vector<int> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<unsigned char>& file,
|
||||
int sin_length,
|
||||
const std::string& dest_file_path)
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<uint32_t>(sin_length),
|
||||
dest_file_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 生成首帧上送报文
|
||||
std::vector<unsigned char> 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 装置标识(device_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<unsigned char>& packet)
|
||||
{
|
||||
current_frame_index = 0;
|
||||
total_frames = 0;
|
||||
all_sent = false;
|
||||
packet.clear();
|
||||
|
||||
std::lock_guard<std::mutex> 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 之后,next_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秒数据记录
|
||||
|
||||
Reference in New Issue
Block a user