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

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

@@ -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;