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输出格式支持
This commit is contained in:
cbb
2026-01-03 18:00:28 +08:00
parent 9c7145ef99
commit 2f482554f0
39 changed files with 1954 additions and 1764 deletions
+161 -35
View File
@@ -47,33 +47,63 @@ void OTAHandler::process() {
}
}
bool OTAHandler::validateApplication() {
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范围内
return (stack_ptr >= 0x20000000 && stack_ptr < 0x20008000) &&
(reset_handler >= APP_START_ADDR &&
reset_handler < (APP_START_ADDR + APP_MAX_SIZE));
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 (!validateApplication())
#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);
@@ -83,41 +113,130 @@ void OTAHandler::jumpToApplication() {
rcu_periph_clock_disable(RCU_TIMER0);
rcu_periph_clock_disable(RCU_DMA0);
// 5. 设置MSP并跳转
uint32_t msp_value = *(__IO uint32_t *)APP_START_ADDR;
__set_MSP(msp_value);
#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;
// 6. 跳转
#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_page_erase(addr);
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;
// 32位对齐写入
for (u32 i = 0; i < size; i += 4) {
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;
memcpy(&word, &data[i], 4);
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;
@@ -125,43 +244,50 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
#if DEBUG_OTA
printf("stage8:OTA_RECEIVING_FIRMWARE\r\n");
#endif
// 数据解包
u32 receive_session_num;
u32 receive_packet_num;
u8 receive_encrypted_data[OTA_PACKET_SIZE];
u32 receive_IFEND;
u8 receive_dataCRC32[4];
receive_session_num = extract_u32_from_4bytes(data);
receive_packet_num = extract_u32_from_4bytes(data + 4);
for (int i = 0; i < 48; i++) {
receive_encrypted_data[i] = data[i + 8];
}
receive_IFEND = extract_u32_from_4bytes(data + 56);
for (int i = 0; i < 4; i++) {
receive_dataCRC32[i] = data[i + 60];
}
// 使用安全的数据解包方式
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, receive_encrypted_data,
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);
return;
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;
}
// 下一个请求
@@ -184,9 +310,9 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
send_error_frame(OTA_ERROR_INVALID_SIZE);
return;
}
// eraseApplicationArea();
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;