Files
GD32_BOOT/Robot_V2/sys/OTA.cpp
T
cbb aefb7d4ee4 feat(ota): 修复备份APP区域恢复功能和OTA流程优化、启用BRS、减小延时
- 添加sendBackup方法用于在备份APP激活时发送确认消息
- 优化OTA跳转逻辑,在jumpToApplication中清除复位标志
- 修复move_app_data函数中数据源地址错误,从备份区域正确读取数据
- 在OTA流程中正确设置APP状态标志,确保应用验证状态管理

refactor(can): 清理调试代码和函数签名优化

- 移除调试用的printf语句和未使用的cstdio头文件
- 统一函数参数类型为u8和u32,提高代码一致性
- 优化CAN通信检查逻辑,移除冗余的调试输出

perf(ota): 优化OTA处理中的延时函数

- 将delay_1ms(1)改为delay_1us(100),提高延时精度
- 添加微秒级延时函数delay_1us实现
- 增加OTA超时时间从10秒到100秒

fix(ota): 修复OTA状态管理和错误处理

- 在各种错误情况下正确设置ota_state为OTA_STATE_IDLE
- 在eraseApplicationArea中正确初始化APP状态标志
- 添加CRC校验失败时的调试输出选项
- 修复数据包大小验证逻辑
2026-01-07 23:14:15 +08:00

723 lines
22 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 <stdint.h>
extern CAN_transmiter CAN0_transmiter; // CAN初始化
OTAHandler ota;
extern "C" {
void canfd_rx_irq_handler(void);
}
inline fmc_state_enum write_ADDRESS(u32 address, u32 data) {
fmc_unlock();
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR);
// 确保使用对齐地址
fmc_state_enum fmc_status = fmc_word_program(address, data);
fmc_lock();
return fmc_status;
}
u8 OTA_SET(u32 addr, u32 data) {
fmc_state_enum fmc_status;
u32 temp_val[OTA_CONFIG_NUM];
volatile u32 *flash_ptr = (volatile u32 *)addr;
temp_val[0] = *flash_ptr;
if (temp_val[0] == data) { // 如果相同
return FLASH_EEPROM_OK; // 成功
}
fmc_unlock();
// 如果不同,且要写0,直接写
if (data == OTA_AVAL) {
fmc_status = write_ADDRESS(addr, data);
fmc_lock();
if (fmc_status == FMC_READY) {
return FLASH_EEPROM_OK; // 成功可以直接退出
}
}
// 如果不同或写入出错,要写1,需要重置,然后再写
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
temp_val[0] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
temp_val[1] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_EN_ADDR;
temp_val[2] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_EN_ADDR;
temp_val[3] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
temp_val[4] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
temp_val[5] = *flash_ptr;
#if EEP_DEBUG
printf("OTA_SET\r\n");
printf("0x%x_0x%x_0x%x_0x%x\r\n", temp_val[0], temp_val[1], temp_val[2],
temp_val[3]);
#endif
fmc_status = fmc_page_erase(n_APP_LATEST_AVAL_ADDR); // 擦除页
if (fmc_status != FMC_READY) {
return FLASH_EEPROM_ERROR; // 擦除错误退出
}
for (int i = 0; i < OTA_CONFIG_NUM; i++) {
if (temp_val[i] == OTA_AVAL and
n_APP_LATEST_AVAL_ADDR + 4 * i != addr) {
fmc_status = write_ADDRESS(n_APP_LATEST_AVAL_ADDR + 4 * i,
OTA_AVAL); // 把需要写入0的写入0
if (fmc_status != FMC_READY) {
fmc_lock();
return FLASH_EEPROM_ERROR; // 写入错误退出
}
}
}
fmc_lock();
return FLASH_EEPROM_OK;
}
/**
* @brief 从4字节数组中提取一个32位无符号整数
* @param array: 4字节数组
* @retval 32位无符号整数
*/
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() {}
/**
* @brief OTA处理函数
* @param 无
* @retval 无
*/
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_1us(100);
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;
volatile u32 *flash_ptr =
(volatile u32 *)n_APP_LATEST_CHECK_ADDR; // 如果是实际可以运行
u32 if_checked = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR; // 如果是实际已刷入
u32 if_aval = *flash_ptr;
send_error_frame(OTA_ERROR_TIMEOUT); // OTA超时
if (if_checked == OTA_AVAL and if_aval == OTA_AVAL) {
OTA_SET(n_APP_LATEST_AVAL_ADDR,
OTA_AVAL); // 实际可用,设置APP为启用
jumpToApplication();
}
}
}
bool validateApplication() {
u32 *app_vector = (u32 *)APPLATEST_START_ADDR;
u32 stack_ptr = app_vector[0];
u32 reset_handler = app_vector[1];
#if DEBUG_OTA
printf("APPLATEST_START_ADDR: 0x%08X\r\n", APPLATEST_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", APPLATEST_START_ADDR,
APPLATEST_START_ADDR + APP_MAX_SIZE);
#endif
// 简单验证:检查栈指针是否在SRAM范围内
bool stack_valid = (stack_ptr >= 0x20000000 && stack_ptr < 0x20008000);
bool reset_valid = (reset_handler >= APPLATEST_START_ADDR &&
reset_handler < (APPLATEST_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;
}
/**
* @brief 跳转应用处理模块
* @param 无
* @retval 无
*/
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
OTA_SET(n_APP_LATEST_AVAL_ADDR, OTA_AVAL); // 设置APP为可用
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_AVAL); // 设置APP为激活
// 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 = APPLATEST_START_ADDR;
// 6. 设置MSP并跳转
uint32_t msp_value = *(__IO uint32_t *)APPLATEST_START_ADDR;
uint32_t reset_handler = *(__IO uint32_t *)(APPLATEST_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);
// 在跳转前清除复位标志
rcu_all_reset_flag_clear();
// 7. 跳转
app_entry();
// 如果程序执行到这里,说明跳转失败
#if DEBUG_OTA
printf("Jump to application failed!\r\n");
#endif
}
/**
* @brief 擦除应用程序区域
* @param 无
* @retval 无
*/
void OTAHandler::eraseApplicationArea() {
OTA_SET(n_APP_LATEST_CHECK_ADDR, OTA_NOT_AVAL); // 设置APP为未确认
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_NOT_AVAL); // 设置APP为未激活
OTA_SET(n_APP_LATEST_AVAL_ADDR, OTA_NOT_AVAL); // 设置APP为不可用
// 擦除APP区域
fmc_unlock();
// 擦除前禁用中断,防止中断处理程序执行期间发生Flash操作导致问题
__disable_irq();
fmc_state_enum fmc_status;
for (u32 addr = APPLATEST_START_ADDR;
addr < (APPLATEST_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 = APPLATEST_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 处理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);
#if DEBUG_OTA
std::printf("CRC32 :%x,%x!\r\n", receive_dataCRC32[0],
calculated_dataCRC32[0]);
#endif
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;
ota_state = OTA_STATE_IDLE;
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;
ota_state = OTA_STATE_IDLE;
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("stage--: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;
ota_state = OTA_STATE_IDLE;
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); // 验证失败
ota_state = OTA_STATE_IDLE;
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;
ota_state = OTA_STATE_IDLE;
send_error_frame(OTA_ERROR_INVALID_HANDSHAKE);
return;
}
}
}
/**
* @brief 发送错误帧
* @param error: 错误码
* @retval 无
*/
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'; // 确保字符串结束
}
/**
* @brief 将0x08010500地址后0xC000大小区域内的数据搬运到0x08011000地址
* @param None
* @retval fmc_state_enum: 操作状态
*/
fmc_state_enum move_app_data() {
fmc_state_enum fmc_status = FMC_READY;
// 关闭全局中断以防止Flash操作期间的中断干扰
__disable_irq();
fmc_unlock();
// 首先擦除目标地址的Flash页面
uint32_t num_pages =
(APP_MAX_SIZE + FMC_PAGE_SIZE - 1) / FMC_PAGE_SIZE; // 向上取整
for (uint32_t i = 0; i < num_pages; i++) {
uint32_t page_addr = APPLATEST_START_ADDR + i * FMC_PAGE_SIZE;
// 擦除页面
fmc_status = fmc_page_erase(page_addr);
if (fmc_status != FMC_READY) {
fmc_lock();
#if OTA_DEBUG
printf("move_app_data erase error\r\n");
#endif
__enable_irq(); // 重新开启中断
return fmc_status;
}
}
// 复制数据 - 按字(32位)进行复制以提高效率
uint32_t offset = 0;
uint32_t write_count = 0; // 记录实际写入的字数
const uint32_t *src_ptr = (const uint32_t *)APPBACK_START_ADDR; // 从备份区域读取
// 预计算源数据的CRC,避免重复访问内存
crc_deinit();
crc_data_register_reset();
uint32_t src_crc = crc_block_data_calculate((uint32_t *)APPBACK_START_ADDR,
APP_MAX_SIZE / 4);
while (offset < APP_MAX_SIZE) {
uint32_t src_data = src_ptr[offset / 4]; // 从备份区域读取数据
// 检查源地址是否为有效的Flash数据(非0xFFFFFFFF表示有数据)
if (src_data != 0xFFFFFFFF) {
// 清除之前的标志位
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR |
FMC_FLAG_PGERR);
fmc_status =
fmc_word_program(APPLATEST_START_ADDR + offset, src_data); // 写入到最新APP区域
// 检查写入操作是否成功
if (fmc_status != FMC_READY) {
#if OTA_DEBUG
printf(
"Flash write failed at offset 0x%08X with status: %d\r\n",
offset, fmc_status);
#endif
fmc_lock();
__enable_irq(); // 重新开启中断
return fmc_status;
}
write_count++;
}
offset += 4;
}
fmc_lock();
// 重新开启全局中断
__enable_irq();
crc_data_register_reset(); // 确保CRC计算从初始状态开始
// 计算目标数据的CRC值
uint32_t dst_crc = crc_block_data_calculate(
(uint32_t *)APPLATEST_START_ADDR, APP_MAX_SIZE / 4);
// 比较CRC值,确保数据完整性
if (src_crc != dst_crc) {
#if OTA_DEBUG
printf("CRC mismatch: src_crc=0x%08X, dst_crc=0x%08X\r\n", src_crc,
dst_crc);
#endif
return (fmc_state_enum)0xFF; // CRC校验失败
}
return fmc_status;
}
/**
* 带密钥的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);
}