Files
GD32_BOOT/Robot_V2/sys/OTA.cpp
T
cbb 2f482554f0 feat(ota): OTA功能测试通过,CANFD解包效率优化
- 添加OTA固件升级功能,包括应用程序验证和跳转机制
- 实现CANFD数据传输协议,支持加密和CRC校验
- 优化CAN通信处理,添加调试输出和错误处理
- 更新RTE组件配置,升级csolution版本到2.12.0
- 增加Flash擦除和写入的安全验证机制
- 添加应用程序区域扫描和验证功能

refactor(can): 重构CAN通信模块和OTA数据处理

- 移除未使用的常量定义和辅助函数
- 改进数据解包和加密解密流程
- 添加条件编译调试输出
- 优化Flash操作的安全性和可靠性

chore(build): 更新项目配置和忽略文件

- 添加tmp/和out/目录到.gitignore
- 扩展ROM0_SIZE从0x0020000到0x08005000
- 添加bin输出格式支持
2026-01-03 18:00:28 +08:00

544 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "OTA.h"
#include "Can.h"
#include "aes128.h"
#include "config.h"
#include "gd32c10x.h" // 主头文件,包含了gd32c10x_crc.h的内容
#include "gd32c10x_fmc.h"
#include "systick.h"
#include <cstdio>
#include <cstring>
#include <flash.h>
#include <stdint.h>
extern CAN_transmiter CAN0_transmiter; // CAN初始化
extern FlashEEPROM flashEEP;
OTAHandler ota;
extern "C" {
void canfd_rx_irq_handler(void);
}
static inline uint32_t extract_u32_from_4bytes(const uint8_t *array) {
return ((uint32_t)array[3] << 24) | ((uint32_t)array[2] << 16) |
((uint32_t)array[1] << 8) | (uint32_t)array[0];
}
void OTAHandler::init() {}
void OTAHandler::process() {
if (ota_state == OTA_STATE_IDLE) {
ota_time = 0; // 重置计时器
static u8 zero[1] = {0};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_WAIT_ID, 0, zero);
#if DEBUG_OTA
printf("OTA status:%d\r\n", ota_state);
#endif
delay_1ms(10);
return;
} else {
delay_1ms(1);
ota_time++;
}
// 检查是否超时(例如:10秒无数据则退出OTA模式)
if (ota_time > OTA_TIMEOUT) { // 10秒超时(10000 x 1ms)
ota_time = 0;
ota_state = OTA_STATE_IDLE;
ota_error = OTA_ERROR_TIMEOUT;
send_error_frame(OTA_ERROR_TIMEOUT); // 验证失败
}
}
bool validateApplication() {
u32 *app_vector = (u32 *)APP_START_ADDR;
u32 stack_ptr = app_vector[0];
u32 reset_handler = app_vector[1];
#if DEBUG_OTA
printf("APP_START_ADDR: 0x%08X\r\n", APP_START_ADDR);
printf("Stack Pointer: 0x%08X\r\n", stack_ptr);
printf("Reset Handler: 0x%08X\r\n", reset_handler);
printf("APP Range: 0x%08X - 0x%08X\r\n", APP_START_ADDR,
APP_START_ADDR + APP_MAX_SIZE);
#endif
// 简单验证:检查栈指针是否在SRAM范围内
bool stack_valid = (stack_ptr >= 0x20000000 && stack_ptr < 0x20008000);
bool reset_valid = (reset_handler >= APP_START_ADDR &&
reset_handler < (APP_START_ADDR + APP_MAX_SIZE));
#if DEBUG_OTA
if (!stack_valid) {
printf("Stack pointer validation failed!\r\n");
}
if (!reset_valid) {
printf("Reset handler validation failed!\r\n");
}
#endif
return stack_valid && reset_valid;
}
void OTAHandler::jumpToApplication() {
#if DEBUG_OTA
printf("try jump to app\r\n");
if (!validateApplication()) {
printf("app valid failed\r\n");
return;
} else {
printf("valid result:successful\r\n");
u8 check_data[2] = {0x0A, 0xAC};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_WAIT_ID, 2, check_data);
}
printf("jumping1\r\n");
#endif
// 1. 关闭所有中断
__disable_irq();
for (int i = 0; i < 8; i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
}
// 2. 重置外设(特别是CAN,防止冲突)
can_deinit(CAN0);
// 3. 重置系统时钟到默认状态
rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
#if DEBUG_OTA
printf("jumping2\r\n");
#endif
// 4. 关闭一些关键外设时钟
rcu_periph_clock_disable(RCU_GPIOA);
rcu_periph_clock_disable(RCU_GPIOB);
rcu_periph_clock_disable(RCU_GPIOC);
rcu_periph_clock_disable(RCU_USART0);
rcu_periph_clock_disable(RCU_CAN0);
rcu_periph_clock_disable(RCU_TIMER0);
rcu_periph_clock_disable(RCU_DMA0);
#if DEBUG_OTA
printf("jumping3\r\n");
#endif
// 5. 设置中断向量表偏移到应用程序起始地址
SCB->VTOR = APP_START_ADDR;
// 6. 设置MSP并跳转
uint32_t msp_value = *(__IO uint32_t *)APP_START_ADDR;
uint32_t reset_handler = *(__IO uint32_t *)(APP_START_ADDR + 4);
typedef void (*AppEntryFunc)(void);
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
#if DEBUG_OTA
printf("jumping5, MSP:0x%08X, Reset Handler:0x%08X\r\n", msp_value,
reset_handler);
#endif
__set_MSP(msp_value);
// 7. 跳转
app_entry();
// 如果程序执行到这里,说明跳转失败
#if DEBUG_OTA
printf("Jump to application failed!\r\n");
#endif
}
/**
* @brief 擦除应用程序区域
* @param 无
* @retval 无
*/
void OTAHandler::eraseApplicationArea() {
// 擦除APP区域
fmc_unlock();
// 擦除前禁用中断,防止中断处理程序执行期间发生Flash操作导致问题
__disable_irq();
fmc_state_enum fmc_status;
for (u32 addr = APP_START_ADDR; addr < (APP_START_ADDR + APP_MAX_SIZE);
addr += FMC_PAGE_SIZE) {
fmc_status = fmc_page_erase(addr);
if (fmc_status != FMC_READY) {
// 如果擦除失败,记录错误并退出
#if DEBUG_OTA
printf("Flash erase failed at address 0x%08X, status: %d\r\n", addr,
fmc_status);
#endif
ota_error = OTA_ERROR_FLASH_ERROR;
send_error_frame(OTA_ERROR_FLASH_ERROR);
break;
}
}
// 重新启用中断
__enable_irq();
fmc_lock();
}
/**
* @brief 写入应用程序数据
* @param offset: 写入偏移量
* @param data: 数据指针
* @param size: 数据大小
* @retval 无
*/
void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
fmc_unlock();
u32 write_addr = APP_START_ADDR + offset;
u32 i = 0;
u8 *src = data;
// 32位对齐写入 - 处理完整的32位字
for (; i <= size - 4; i += 4) {
fmc_word_program(write_addr + i, *(u32 *)&src[i]);
}
// 处理剩余字节(如果有的话)
if (i < size) {
u32 word = 0;
u8 *word_ptr = (u8 *)&word;
u32 remaining_bytes = size - i;
// 直接复制剩余字节到word变量
for (u32 j = 0; j < remaining_bytes; j++) {
word_ptr[j] = src[i + j];
}
fmc_word_program(write_addr + i, word);
}
fmc_lock();
}
/**
* @brief 验证应用程序数据
* @param offset: 写入偏移量
* @param data: 原始数据指针
* @param size: 数据大小
* @retval true if verification passes, false otherwise
*/
bool OTAHandler::verifyApplicationData(u32 offset, u8 *data, u32 size) {
u32 verify_addr = APP_START_ADDR + offset;
for (u32 i = 0; i < size; i++) {
if (((u8 *)verify_addr)[i] != data[i]) {
#if DEBUG_OTA
printf("Data verification failed at offset %d, expected 0x%02X, "
"got 0x%02X\r\n",
i, data[i], ((u8 *)verify_addr)[i]);
#endif
return false;
}
}
return true;
}
/**
* @brief 处理OTA数据包
* @param id: CAN帧ID
* @param data: CAN帧数据
* @param len: CAN帧数据长度
* @retval 无
*/
void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
if (id == CANFD_OTA_DATA_ID) {
ota_time = 0;
if (len == 64 and ota_state == OTA_STATE_RECEIVING_FIRMWARE) {
#if DEBUG_OTA
printf("stage8:OTA_RECEIVING_FIRMWARE\r\n");
#endif
// 使用安全的数据解包方式
u32 receive_session_num = extract_u32_from_4bytes(data);
u32 receive_packet_num = extract_u32_from_4bytes(data + 4);
u32 receive_IFEND = extract_u32_from_4bytes(data + 56);
// 直接使用数据指针,避免不必要的内存复制
const u8 *receive_encrypted_data =
data + 8; // 加密数据从偏移8字节开始
const u8 *receive_dataCRC32 = data + 60; // CRC数据从偏移60字节开始
// 解密 - 使用栈上数组存储解密结果
u8 decrypted_data[OTA_PACKET_SIZE];
u8 calculated_dataCRC32[4];
aes128_set_key(&aes_ctx, current_K_session);
aes128_ecb_decrypt_48bytes(&aes_ctx,
const_cast<u8 *>(receive_encrypted_data),
decrypted_data);
// 计算解密后CRC数据
calculate_crc32_with_key(current_K_session, decrypted_data,
calculated_dataCRC32);
// CRC数据匹配
if (memcmp(receive_dataCRC32, calculated_dataCRC32, SIZE_U32) !=
0) {
ota_error = OTA_ERROR_INVALID_CRC;
send_error_frame(OTA_ERROR_INVALID_CRC);
receive_packet_num -= 1;
} else {
// 写入Flash前验证数据
u32 offset = receive_packet_num * OTA_PACKET_SIZE;
if (offset + OTA_PACKET_SIZE <= APP_MAX_SIZE) {
writeApplicationData(offset, decrypted_data,
OTA_PACKET_SIZE);
} else {
ota_error = OTA_ERROR_INVALID_SIZE;
send_error_frame(OTA_ERROR_INVALID_SIZE);
}
}
if (receive_IFEND == 0xFFFFFFFF) { // 接收到尾帧,发送结束信号
u8 pack_number[4] = {0xFF, 0xFF, 0xFF, 0xFF};
CAN0_transmiter.sendDATA_ACK(CANFD_OTA_ACK_ID, pack_number);
ota_state = OTA_STATE_FINISHED;
jumpToApplication();
return;
}
// 下一个请求
u32 request_packet = receive_packet_num + 1;
u8 pack_number[4];
// 封包
memcpy(&pack_number, &request_packet, 4);
CAN0_transmiter.sendDATA_ACK(CANFD_OTA_ACK_ID, pack_number);
} else if (len == 4 and ota_state == OTA_STATE_CHECKING_FIRMWARE) {
#if DEBUG_OTA
printf("stage7:OTA_STATE_CHECKING_FIRMWARE\r\n");
#endif
// OTA请求包
u32 new_size = *(u32 *)data;
if (new_size <= APP_MAX_SIZE) {
expected_size = new_size;
received_size = 0;
} else {
ota_error = OTA_ERROR_INVALID_SIZE;
send_error_frame(OTA_ERROR_INVALID_SIZE);
return;
}
u8 send_data[6] = {0xBA, 0xC0, 0x00,
0x00, 0x00, 0x00}; // 确认开始传输
eraseApplicationArea();
// 发送接收包0请求
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 6, send_data);
ota_state = OTA_STATE_RECEIVING_FIRMWARE;
} else if (len == 2 and ota_state == OTA_STATE_FINISHED) {
#if DEBUG_OTA
printf("stage8:OTA_STATE_FINISHED\r\n");
#endif
u8 send_data[2] = {0x0A, 0xAC}; // 确认开始传输
// 4. 验证成功 - 发送最终ACK
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, send_data);
} else {
ota_error = OTA_ERROR_INVALID_PACKET;
send_error_frame(OTA_ERROR_INVALID_PACKET);
}
} else if (id == CANFD_OTA_REQ_ID) {
ota_time = 0;
#if DEBUG_OTA
printf("stage2:OTA_STATE_WAITING_RANDOM\r\n");
#endif
if (data[0] == 0x00 and data[1] == 0xAC and len == 2 and
ota_state == OTA_STATE_IDLE) { // 收到发起信号
u8 send_data[2] = {0x00, 0xac}; // 确认握手开始,请求随机数
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2,
send_data); // 发送握手开始信号
ota_state = OTA_STATE_WAITING_RANDOM;
} else if (len == 16 and ota_state == OTA_STATE_WAITING_RANDOM) {
#if DEBUG_OTA
printf("stage4:OTA_STATE_WAITING_CONFIRM\r\n");
#endif
while (len-- > 0) {
nonce_server[len] = data[len];
}
// 1. 获取设备唯一码
getDeviceSerialNumber(device_uid);
// 2. 初始化AES上下文(设置主密钥)
aes128_set_key(&aes_ctx, K_master);
// 3. 生成会话密钥 K_session (16字节)
u8 K_session[16];
aes128_encrypt_block(&aes_ctx, nonce_server,
K_session); // 用主密钥加密随机数
// 4. 用主密钥加密明文 (AES-128-ECB)
u8 encrypted_Ksession[16];
u8 temp_block[AES_BLOCK_SIZE];
// 加密第一个16字节块
aes128_encrypt_block(&aes_ctx, K_session, temp_block);
memcpy(encrypted_Ksession, temp_block, 16);
// 5. 构造握手响应包 (36字节)
u8 handshake_response[36];
// 5.1 前12字节:设备UID
memcpy(handshake_response, device_uid, 12);
// 5.2 接下来8字节:nonce后半部分
memcpy(handshake_response + 12, nonce_server + 8, 8);
// 5.3 最后16字节:加密数据的K-session
memcpy(handshake_response + 20, encrypted_Ksession, 16);
// 6. 通过CAN发送响应
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 36,
handshake_response);
// 7. 保存会话密钥供后续使用
memcpy(current_K_session, K_session, 16);
// 8. 更新状态机
ota_state = OTA_STATE_WAITING_CONFIRM;
} else if (len == 16 and ota_state == OTA_STATE_WAITING_CONFIRM) {
#if DEBUG_OTA
printf("stage6:OTA_STATE_CHECKING_SESSION\r\n");
#endif
u8 plaintext[16];
u8 expected[16];
// 1. 用K_session解密
u8 encrypted_confirm[16];
memcpy(encrypted_confirm, data, 16);
aes128_set_key(&aes_ctx, current_K_session);
aes128_decrypt_block(&aes_ctx, encrypted_confirm, plaintext);
// 2. 计算期望值 (nonce_server XOR 0x55)
// 注意:需要保存原始的nonce_server
for (int i = 0; i < 16; i++) {
expected[i] = nonce_server[i] ^ 0x55;
}
// 3. 验证解密结果
if (memcmp(plaintext, expected, 16) != 0) {
// 验证失败 - 可能密钥错误或攻击
ota_error = OTA_ERROR_INVALID_KEY;
send_error_frame(OTA_ERROR_INVALID_KEY); // 验证失败
// reset_ota_state();
return;
}
u8 send_data[2] = {0xBA, 0xC0}; // 确认开始传输
// 4. 验证成功 - 发送最终ACK
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, send_data);
// 5. 更新状态 - 进入固件接收阶段
ota_state = OTA_STATE_CHECKING_FIRMWARE;
} else {
// 其他握手异常
ota_error = OTA_ERROR_INVALID_HANDSHAKE;
send_error_frame(OTA_ERROR_INVALID_HANDSHAKE);
return;
}
}
}
void send_error_frame(u8 error) {
u8 error_frame[1] = {error};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 1, error_frame);
}
/**
* @brief 获取GD32设备唯一码
* @param buffer 存储唯一码的缓冲区,至少需要12字节
* @return void
*/
void getDeviceSerialNumber(u8 *buffer) {
uint32_t serial_msb = DEVICE_SERIAL_ADDR_MSB;
uint32_t serial_mid = DEVICE_SERIAL_ADDR_MID;
uint32_t serial_lsb = DEVICE_SERIAL_ADDR_LSB;
// 将96位唯一ID复制到缓冲区 (以小端序存储)
for (int i = 0; i < 4; i++) {
buffer[i] = (u8)(serial_lsb >> (i * 8));
buffer[i + 4] = (u8)(serial_mid >> (i * 8));
buffer[i + 8] = (u8)(serial_msb >> (i * 8));
}
}
/**
* @brief 获取GD32设备唯一码为字符串格式
* @param str 存储唯一码字符串的缓冲区,至少需要25字节(包含结束符)
* @return void
*/
void getDeviceSerialNumberString(char *str) {
u8 serial[12];
getDeviceSerialNumber(serial);
// 将字节序列转换为十六进制字符串表示
for (int i = 0; i < 12; i++) {
sprintf(&str[i * 2], "%02X", serial[i]);
}
str[24] = '\0'; // 确保字符串结束
}
/**
* 带密钥的CRC32校验函数
*
* @param key 16字节密钥
* @param data 48字节待校验数据
* @param output 4字节输出缓冲区,存储CRC32校验值
*
* 特点:
* - 使用标准CRC32算法
* - 16字节密钥用于初始化CRC32状态
*/
void calculate_crc32_with_key(const uint8_t *key, const uint8_t *data,
u8 *output) {
// CRC32查找表(标准多项式0xEDB88320)
static const uint32_t crc_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
// 用16字节密钥初始化CRC32状态
uint32_t crc = 0xFFFFFFFF;
for (int i = 0; i < 16; i++) {
crc = crc_table[(crc ^ key[i]) & 0xFF] ^ (crc >> 8);
}
// 计算48字节数据的CRC32
for (int i = 0; i < 48; i++) {
crc = crc_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
}
// 取反得到最终结果
crc = ~crc;
// 将CRC32结果拆分为4字节(小端格式)
output[0] = (uint8_t)(crc >> 0);
output[1] = (uint8_t)(crc >> 8);
output[2] = (uint8_t)(crc >> 16);
output[3] = (uint8_t)(crc >> 24);
}