修改了装置重启方式,去除了外部调用的校验流程,现在直接在内部自动完成。
新增了装置升级的正式流程。
This commit is contained in:
@@ -23,6 +23,47 @@ static uv_loop_t* global_loop = nullptr;
|
||||
static uv_timer_t monitor_timer;
|
||||
extern SafeMessageQueue message_queue;
|
||||
|
||||
// 生成与 C# CreateNormalCrc32Table 完全对应的表
|
||||
static std::array<uint32_t, 256> CreateNormalCrc32Table_Char(uint32_t poly)
|
||||
{
|
||||
std::array<uint32_t, 256> table{};
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
uint32_t data = static_cast<uint32_t>(i) << 24;
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
bool flag = (data & 0x80000000u) == 0x80000000u;
|
||||
if (flag)
|
||||
{
|
||||
data = (data << 1) ^ poly;
|
||||
}
|
||||
else
|
||||
{
|
||||
data <<= 1;
|
||||
}
|
||||
}
|
||||
table[i] = data;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
// 与 C# CalcNoemalCrc32 完全对应
|
||||
static uint32_t CalcNormalCrc32_Char(const std::vector<unsigned char>& bytes,
|
||||
uint32_t poly = 0x04C11DB7u)
|
||||
{
|
||||
static const std::array<uint32_t, 256> table = CreateNormalCrc32Table_Char(poly);
|
||||
|
||||
uint32_t crc = 0xFFFFFFFFu;
|
||||
for (size_t i = 0; i < bytes.size(); ++i)
|
||||
{
|
||||
crc = (crc << 8) ^ table[((crc >> 24) & 0xFFu) ^ bytes[i]];
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
// ClientContext 实现
|
||||
ClientContext::ClientContext(uv_loop_t* loop, const DeviceInfo& device, int index)
|
||||
: loop(loop), state(ConnectionState::DISCONNECTED),
|
||||
@@ -348,6 +389,140 @@ void ClientContext::clear_float_cache() {
|
||||
std::lock_guard<std::mutex> lock(float_cache_mutex_);
|
||||
point_float_cache_.clear();
|
||||
}
|
||||
|
||||
//升级管理相关函数
|
||||
/**
|
||||
* @brief 程序切片函数
|
||||
* @param file 升级程序文件
|
||||
* @param frame_index 要发送的帧序号
|
||||
* @param frame_payload_size 单帧数据长
|
||||
* @return 切片数据
|
||||
*/
|
||||
static std::vector<unsigned char> slice_frame_data(const std::vector<unsigned char>& file,
|
||||
uint32_t frame_index,
|
||||
uint32_t frame_payload_size)
|
||||
{
|
||||
const uint64_t offset = static_cast<uint64_t>(frame_index) * frame_payload_size;
|
||||
if (offset >= file.size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const uint64_t remain = file.size() - offset;
|
||||
const uint64_t copy_len = std::min<uint64_t>(remain, frame_payload_size);
|
||||
|
||||
return std::vector<unsigned char>(
|
||||
file.begin() + static_cast<std::ptrdiff_t>(offset),
|
||||
file.begin() + static_cast<std::ptrdiff_t>(offset + copy_len));
|
||||
}
|
||||
/**
|
||||
* @brief 装置升级参数初始化
|
||||
* @param file 升级程序文件
|
||||
* @param frame_payload_size 单帧数据长
|
||||
* @return 是否需要升级
|
||||
*/
|
||||
bool ClientContext::prepare_upgrade_task(const std::vector<unsigned char>& file, uint32_t frame_payload_size)
|
||||
{
|
||||
if (file.empty() || frame_payload_size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(upgrade_mutex_);
|
||||
|
||||
upgrade_task_.file_data = file;
|
||||
upgrade_task_.file_size = static_cast<uint32_t>(file.size());
|
||||
upgrade_task_.file_crc = CalcNormalCrc32_Char(file, 0x04C11DB7u);
|
||||
upgrade_task_.frame_payload_size = frame_payload_size;
|
||||
upgrade_task_.total_frames =
|
||||
static_cast<uint32_t>((file.size() + frame_payload_size - 1) / frame_payload_size);
|
||||
upgrade_task_.next_frame_index = 0;
|
||||
upgrade_task_.active = (upgrade_task_.total_frames > 0);
|
||||
|
||||
return upgrade_task_.active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 生成升级传输的下一帧报文
|
||||
* @param out_packet 升级报文
|
||||
* @param finished 是否结束
|
||||
* @return 是否继续
|
||||
*/
|
||||
bool ClientContext::build_next_upgrade_packet(std::vector<unsigned char>& out_packet, bool& finished)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(upgrade_mutex_);
|
||||
|
||||
finished = false;
|
||||
out_packet.clear();
|
||||
|
||||
if (!upgrade_task_.active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (upgrade_task_.next_frame_index >= upgrade_task_.total_frames) {
|
||||
finished = true;
|
||||
upgrade_task_.active = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> frame_data =
|
||||
slice_frame_data(upgrade_task_.file_data,
|
||||
upgrade_task_.next_frame_index,
|
||||
upgrade_task_.frame_payload_size);
|
||||
|
||||
if (frame_data.empty()) {
|
||||
upgrade_task_.active = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
out_packet = generate_upgrade_start_message(
|
||||
frame_data,
|
||||
upgrade_task_.next_frame_index, // 0-based,内部会 +1
|
||||
upgrade_task_.file_size,
|
||||
upgrade_task_.total_frames,
|
||||
upgrade_task_.file_crc
|
||||
);
|
||||
|
||||
++upgrade_task_.next_frame_index;
|
||||
|
||||
if (upgrade_task_.next_frame_index >= upgrade_task_.total_frames) {
|
||||
finished = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前升级的当前帧和总帧数
|
||||
* @param current_frame_index 当前帧
|
||||
* @param total_frames 总帧数
|
||||
* @return 是否正常
|
||||
*/
|
||||
bool ClientContext::get_upgrade_progress(uint32_t& current_frame_index, uint32_t& total_frames) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(upgrade_mutex_);
|
||||
|
||||
if (!upgrade_task_.active) {
|
||||
current_frame_index = 0;
|
||||
total_frames = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
current_frame_index = upgrade_task_.next_frame_index;
|
||||
total_frames = upgrade_task_.total_frames;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientContext::clear_upgrade_task()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(upgrade_mutex_);
|
||||
upgrade_task_ = UpgradeTask{};
|
||||
}
|
||||
|
||||
bool ClientContext::has_active_upgrade_task() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(upgrade_mutex_);
|
||||
return upgrade_task_.active;
|
||||
}
|
||||
|
||||
// 版本比较函数的辅助函数:分割字符串并转换为整数向量
|
||||
std::vector<int> splitVersionString(const std::string& versionStr) {
|
||||
std::vector<int> segments;
|
||||
@@ -1744,8 +1919,8 @@ bool ClientManager::set_preupgrade_action_to_device(const std::string& identifie
|
||||
if (ctx->device_info.device_id == identifier ||
|
||||
ctx->device_info.mac == identifier)
|
||||
{
|
||||
//设置用于校验的预升级文件
|
||||
ctx->set_preupgrade_filepath(path);
|
||||
//设置用于校验的预升级文件 校验采用默认生成的文件 暂时不使用
|
||||
//ctx->set_preupgrade_filepath(path);
|
||||
// 生成预升级报文
|
||||
auto packet = generate_preupgrade_message();
|
||||
|
||||
@@ -1763,6 +1938,111 @@ bool ClientManager::set_preupgrade_action_to_device(const std::string& identifie
|
||||
return false; // 设备未找到
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 装置升级动作 发送初始帧
|
||||
* @param file 升级程序文件
|
||||
* @param sin_length 上送单帧长度
|
||||
* @return 发送结果
|
||||
*/
|
||||
bool ClientManager::send_upgrade_action_to_device(const std::string& identifier, const std::vector<unsigned char>& file,int sin_length) {
|
||||
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) {
|
||||
|
||||
//此处计算文件总大小,将参数程序文件分割成依照单帧长度的多组文件,计算文件crc,计算保存总帧数,保存当前帧计数
|
||||
|
||||
//之后重新写一个ClientManager的函数,用于将之前计算出的参数验证正常后依次自动生成报文并执行,不要直接在这里执行,因为后续会在别的地方调用,防止需要一直获取所有参数再生成报文,直接打包方便调用。
|
||||
|
||||
// 1. 先准备升级任务
|
||||
if (!ctx->prepare_upgrade_task(file, static_cast<uint32_t>(sin_length))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 生成首帧升级报文
|
||||
std::vector<unsigned char> first_packet;
|
||||
bool finished = false;
|
||||
if (!ctx->build_next_upgrade_packet(first_packet, finished) || first_packet.empty()) {
|
||||
ctx->clear_upgrade_task();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 添加动作到队列 (状态: 读取文件目录)
|
||||
ctx->add_action(DeviceState::SET_UPGRADE, first_packet);
|
||||
|
||||
// 如果当前空闲则立即执行
|
||||
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_upgrade_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_upgrade_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_upgrade_packet(packet, finished)) {
|
||||
packet.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// build_next_upgrade_packet 之后,next_frame_index 已经自增
|
||||
// 这里再更新一次进度给外部
|
||||
ctx->get_upgrade_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秒数据记录
|
||||
@@ -1814,10 +2094,10 @@ bool ClientManager::read_eventlog_action_to_device(const std::string& identifier
|
||||
ctx->device_info.mac == identifier)
|
||||
{
|
||||
ctx->event_lineNo = monitorPoint;
|
||||
// 生成定值描述报文
|
||||
// 生成补招报文
|
||||
auto packet = generate_recallevent_message(Time1, Time2, eventType, monitorPoint);
|
||||
|
||||
// 添加动作到队列 (状态: 读取文件目录)
|
||||
// 添加动作到队列 (状态: 补招事件)
|
||||
ctx->add_action(DeviceState::READING_EVENTLOG, packet);
|
||||
|
||||
// 如果当前空闲则立即执行
|
||||
|
||||
Reference in New Issue
Block a user