添加了装置预升级校验流程

This commit is contained in:
2026-03-05 20:56:14 +08:00
parent bf1eccf436
commit 93def18fbd
6 changed files with 264 additions and 14 deletions

View File

@@ -658,13 +658,29 @@ std::vector<unsigned char> generate_machineversion_message()
// <20><><EFBFBD><EFBFBD>10<31>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>Ϊ0
std::vector<unsigned char> DataBuf(10, 0x00);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3<EFBFBD><33>ֵΪ1<EFBFBD><EFBFBD><EFBFBD><EFBFBD>4<EFBFBD><EFBFBD><EFBFBD>ֽڣ<EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3<EFBFBD><33>ֵΪ2<EFBFBD><EFBFBD><EFBFBD><EFBFBD>4<EFBFBD><EFBFBD><EFBFBD>ֽڣ<EFBFBD>
DataBuf[3] = 0x02;
// <20><><EFBFBD><EFBFBD>ͨ<EFBFBD>ñ<EFBFBD><C3B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɺ<EFBFBD><C9BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>14<31><34>Ӧװ<D3A6><D7B0>״̬<D7B4><CCAC>ȡ
return GetMsg(DataBuf, static_cast<unsigned char>(MsgRequestType::Request_Read_RunningInformation));
}
/**
* @brief <20><><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><C4B5>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>
*/
std::vector<unsigned char> generate_preupgrade_message()
{
// <20><><EFBFBD><EFBFBD>10<31>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>Ϊ0
std::vector<unsigned char> DataBuf(10, 0x00);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3<EFBFBD><33>ֵΪ4<CEAA><34><EFBFBD><EFBFBD>4<EFBFBD><34><EFBFBD>ֽڣ<D6BD>
DataBuf[3] = 0x04;
// <20><><EFBFBD><EFBFBD>ͨ<EFBFBD>ñ<EFBFBD><C3B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɺ<EFBFBD><C9BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>14<31><34>Ӧװ<D3A6><D7B0>״̬<D7B4><CCAC>ȡ
return GetMsg(DataBuf, static_cast<unsigned char>(MsgRequestType::Request_Read_RunningInformation));
}
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD>ö<EFBFBD>ʱ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>
* @param time <20>·<EFBFBD><C2B7>Ķ<EFBFBD>ʱʱ<CAB1><CAB1> (tmֵ)
@@ -796,3 +812,4 @@ std::vector<unsigned char> generate_control_message(uint8_t type, uint8_t ctrlfl
return GetMsg(DataBuf, static_cast<unsigned char>(MsgRequestType::Request_Ctrl));
}

View File

@@ -2411,6 +2411,11 @@ std::vector<unsigned char> generate_machinestatus_message();
* @return <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><C4B5>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>
*/
std::vector<unsigned char> generate_machineversion_message();
/**
* @brief <20><><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><C4B5>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>
*/
std::vector<unsigned char> generate_preupgrade_message();
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD>ö<EFBFBD>ʱ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>
* @param time <20>·<EFBFBD><C2B7>Ķ<EFBFBD>ʱʱ<CAB1><CAB1> (tmֵ)

View File

@@ -1713,10 +1713,10 @@ bool ClientManager::read_devversion_action_to_device(const std::string& identifi
if (ctx->device_info.device_id == identifier ||
ctx->device_info.mac == identifier)
{
// 生成定值描述报文
// 生成版本配置报文
auto packet = generate_machineversion_message();
// 添加动作到队列 (状态: 读取文件目录)
// 添加动作到队列 (状态: 读取装置版本信息)
ctx->add_action(DeviceState::READING_DEVVERSION, packet);
// 如果当前空闲则立即执行
@@ -1730,6 +1730,39 @@ bool ClientManager::read_devversion_action_to_device(const std::string& identifi
return false; // 设备未找到
}
/**
* @brief 生成预升级校验报文
* @param path 预校验文件路径
* @return 包含完整报文的字节向量
*/
bool ClientManager::set_preupgrade_action_to_device(const std::string& identifier, const std::string& 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)
{
//设置用于校验的预升级文件
ctx->set_preupgrade_filepath(path);
// 生成预升级报文
auto packet = generate_preupgrade_message();
// 添加动作到队列 (状态: 预升级校验)
ctx->add_action(DeviceState::SET_PREUPGRADE, packet);
// 如果当前空闲则立即执行
if (ctx->current_state_ == DeviceState::IDLE) {
ctx->process_next_action();
}
return true; // 成功添加
}
}
return false; // 设备未找到
}
/**
* @brief 生成装置控制命令报文
* @param type 命令类型 1-装置复位2-启动录波3-启动200ms数据记录4-启动3秒数据记录
@@ -1940,6 +1973,7 @@ bool ClientManager::update_current_filename(const std::string& identifier,
return false;
}
//获取当前正在下载的文件名
std::string ClientManager::get_current_filename(const std::string& identifier) {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& pair : clients_) {
@@ -1950,4 +1984,17 @@ std::string ClientManager::get_current_filename(const std::string& identifier) {
}
}
return "";
}
//获取用于预校验的文件路径
std::string ClientManager::get_preupgrade_filepath(const std::string& identifier) {
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) {
return ctx->get_preupgrade_filepath();
}
}
return "";
}

View File

@@ -66,6 +66,7 @@ enum class DeviceState {
READING_EVENTLOG, // <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>־
READING_STATSFILE, // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̬<EFBFBD><CCAC><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
SET_CTRL, // <20><><EFBFBD><EFBFBD>װ<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
SET_PREUPGRADE, // װ<><D7B0>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD>У<EFBFBD><D0A3>
// <20>ɸ<EFBFBD><C9B8><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD>Ӹ<EFBFBD><D3B8><EFBFBD>״̬
CUSTOM_ACTION // <20>Զ<EFBFBD><D4B6><EFBFBD><E5B6AF>
};
@@ -204,6 +205,7 @@ public:
std::vector<FileDownloadPacket> file_download_cache_; // <20>ļ<EFBFBD><C4BC><EFBFBD>Ƭ<EFBFBD><C6AC><EFBFBD><EFBFBD>
std::string current_filename_; // <20><>ǰ<EFBFBD><C7B0><EFBFBD>ص<EFBFBD><D8B5>ļ<EFBFBD><C4BC><EFBFBD>
std::string preupgrade_filepath_; // Ԥ<><D4A4><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>
std::mutex file_cache_mutex_; // <20><><EFBFBD><EFBFBD><E6BBA5><EFBFBD><EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>Ƭ<EFBFBD><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
@@ -250,6 +252,18 @@ public:
std::lock_guard<std::mutex> lock(file_cache_mutex_);
return current_filename_;
}
//<2F><><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>
void set_preupgrade_filepath(const std::string& filepath) {
std::lock_guard<std::mutex> lock(file_cache_mutex_);
preupgrade_filepath_ = filepath;
}
// <20><>ȡԤ<C8A1><D4A4><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>
std::string get_preupgrade_filepath() {
std::lock_guard<std::mutex> lock(file_cache_mutex_);
return preupgrade_filepath_;
}
private:
int index_;
@@ -406,6 +420,8 @@ public:
bool update_current_filename(const std::string& identifier, const std::string& filename);
std::string get_current_filename(const std::string& identifier);
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ԤУ<D4A4><D0A3><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>
std::string get_preupgrade_filepath(const std::string& identifier);
//ˢ<>¿ͻ<C2BF><CDBB><EFBFBD>װ<EFBFBD><D7B0><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD>ͨѶ<CDA8><D1B6><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
bool set_cloudmessage_time(const std::string& identifier);
@@ -449,6 +465,13 @@ public:
//װ<><D7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>
bool set_righttime_action_to_device(const std::string& identifier);
/**
* @brief <20><><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><E9B1A8>
* @param path ԤУ<D4A4><D0A3><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>
* @return <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><C4B5>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>
*/
bool set_preupgrade_action_to_device(const std::string& identifier, const std::string& path);
//<2F><EFBFBD><E8B1B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
bool get_dev_status(const std::string& identifier);
/**

View File

@@ -49,23 +49,89 @@ std::string extract_filename(const std::string& path) {
return path;
}
//文件crc校验函数
uint16_t crc_16_new(const uint8_t* buf, uint32_t len) {
uint16_t crc = 0xffff;
for (uint32_t i = 0; i < len; i++) {
crc = (uint16_t)(crc ^ buf[i]);
for (int j = 0; j < 8; j++) {
if (crc & 1) {
crc = (uint16_t)((crc >> 1) ^ 0xA001);
// 生成与 C# CreateNormalCrc32Table 完全对应的表
static std::array<uint32_t, 256> CreateNormalCrc32Table(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 {
crc = (uint16_t)(crc >> 1);
else
{
data <<= 1;
}
}
table[i] = data;
}
return table;
}
// 与 C# CalcNoemalCrc32 完全对应
static uint32_t CalcNormalCrc32(const std::vector<uint8_t>& bytes, uint32_t poly)
{
auto table = CreateNormalCrc32Table(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;
}
/* 生成预升级校验文件 算法 */
int new_tcp_pre_upgrade_message_create(uint8_t* buf, uint32_t len)
{
uint16_t i, j;
uint16_t value = 0xFFFF;
uint16_t factor = 0xA001;
if (len > 10 * 1024) {
len = 10 * 1024;
}
for (i = 0; i < len; i++)
{
value = value ^ static_cast<uint16_t>(i + 1);
for (j = 0; j < 8; j++)
{
if ((value & 1) == 1) {
value = static_cast<uint16_t>((value >> 1) ^ factor);
}
else {
value = static_cast<uint16_t>(value >> 1);
}
}
buf[i] = static_cast<uint8_t>(value & 0xFF);
}
return static_cast<int>(len);
}
//生成预升级校验文件
std::vector<uint8_t> GeneratePreUpgradeFileFromLengthBytes(uint32_t fileLen)
{
if (fileLen > 10 * 1024) {
throw std::runtime_error("Pre-upgrade file length exceeds maximum allowed size.");
}
std::vector<uint8_t> fileData(fileLen);
int actualLen = new_tcp_pre_upgrade_message_create(fileData.data(), fileLen);
fileData.resize(actualLen);
return fileData;
}
//消息处理逻辑
void process_received_message(string mac, string id,const char* data, size_t length) {
// 实际的消息处理逻辑
@@ -94,6 +160,7 @@ void process_received_message(string mac, string id,const char* data, size_t len
ClientManager::instance().set_cloud_status(id, 1); //设置了云前置登录状态为已登录
ClientManager::instance().read_devversion_action_to_device(id);//主动触发,读取装置版本配置信息,仅在装置登录后执行一次,当前获取版本信息确认对时报文结构。
ClientManager::instance().set_preupgrade_action_to_device(id, "");//装置升级预校验流程 校验文件自动生成 当前填空
//ClientManager::instance().set_ctrl_action_to_device(id,0x01,0x00);//尝试装置重启指令!第一步校验
//ClientManager::instance().set_ctrl_action_to_device(id, 0x01, 0x01);//尝试装置重启指令!校验完毕后尝试执行重启指令
@@ -2269,6 +2336,97 @@ void process_received_message(string mac, string id,const char* data, size_t len
}
break;
case DeviceState::SET_PREUPGRADE:
//装置预升级校验
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_RunningInformation)) {
// 获取解析后的数据体
std::vector<uint8_t>& recvData = parser.RecvData;
// 检查数据长度是否足够
if (recvData.size() < 2) {
//装置上送的预校验文件异常!预校验失败!
std::cerr << "Invalid running information data: too short ("
<< recvData.size() << " bytes)" << std::endl;
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// 提取有效载荷长度
size_t payloadLength = recvData.size() - 2;
// 复制有效载荷数据
std::vector<uint8_t> payloadBytes(payloadLength);
if (recvData.size() >= 2 + payloadLength) {
std::copy(recvData.begin() + 2, recvData.begin() + 2 + payloadLength, payloadBytes.begin());
}
else {
//装置上送的预校验文件异常!预校验失败!
std::cerr << "Invalid payload length: " << payloadLength
<< ", available: " << (recvData.size() - 2) << std::endl;
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// payload 至少要有 4 个字节,才能取前四位作为 32 位整数
if (payloadBytes.size() < 4) {
//装置上送的预校验文件异常!预校验失败!
std::cerr << "Invalid payloadBytes: too short to extract int32 ("
<< payloadBytes.size() << " bytes)" << std::endl;
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// 取前 4 个字节并转换为 32 位整数(按大端序)
int32_t dataLength =
(static_cast<int32_t>(payloadBytes[0]) << 24) |
(static_cast<int32_t>(payloadBytes[1]) << 16) |
(static_cast<int32_t>(payloadBytes[2]) << 8) |
(static_cast<int32_t>(payloadBytes[3]));
// 去掉前 4 个字节,取出剩余部分
std::vector<uint8_t> realPayload(payloadBytes.begin() + 4, payloadBytes.end());
// 检查剩余部分长度是否与前面的 32 位整数一致
if (dataLength < 0 || realPayload.size() != static_cast<size_t>(dataLength)) {
std::cerr << "Payload length mismatch: expected " << dataLength
<< ", actual " << realPayload.size() << std::endl;
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// 到这里说明:
// 1. 前4字节已经解析成 int32_t dataLength
// 2. 剩余数据保存在 realPayload 中
// 3. realPayload.size() == dataLength
std::cout << "********* wait crc *********" << std::endl;
// 用前4字节生成本地“标准文件内容”
std::vector<uint8_t> localFile = GeneratePreUpgradeFileFromLengthBytes(dataLength);
// 计算 CRC
uint32_t crc = CalcNormalCrc32(realPayload, 0x04C11DB7u);
uint32_t generatedCrc = CalcNormalCrc32(localFile, 0x04C11DB7u);
std::cout << "Generated CRC = 0x" << std::hex << std::uppercase << generatedCrc << std::endl;
std::cout << "Received CRC = 0x" << std::hex << std::uppercase << crc << std::endl;
std::cout << std::dec;
if (generatedCrc != crc) {
//crc 校验失败 后续升级停止!
std::cerr << "CRC verify failed." << std::endl;
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// 预升级校验结束成功,调整为空闲,处理后续工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
// 预升级校验失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::CUSTOM_ACTION:
// 自定义动作状态
std::cout << "CUSTOM_ACTION state: Processing custom response from " << mac << std::endl;

View File

@@ -380,7 +380,7 @@ int main(int argc ,char** argv) {//
std::cerr << "process param error,exit" << std::endl;
return 1;
}
init_daemon();
//init_daemon();
srand(time(NULL)); // <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <20><>ʼ<EFBFBD><CABC><EFBFBD>߳<EFBFBD><DFB3><EFBFBD><EFBFBD><EFBFBD>