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校验失败时的调试输出选项
- 修复数据包大小验证逻辑
This commit is contained in:
cbb
2026-01-07 23:14:15 +08:00
parent c7c4451d57
commit aefb7d4ee4
18 changed files with 1384 additions and 1328 deletions
+5 -13
View File
@@ -6,7 +6,6 @@
#include "gd32c10x_dma.h"
#include "gd32c10x_gpio.h"
#include "main.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdint.h>
@@ -191,30 +190,19 @@ u8 CAN_transmiter::init() {
void CAN_transmiter::communication_check() {
// CAN0 发送数据标志
if (SET == can0_send_flag) {
// printf("\r\n can0 %X receive data:", receive_message.rx_efid);
// CAN0_transmiter.CAN_all_Send();
// CANFD_all_Send();
can0_send_flag = RESET;
}
// CAN0 接收数据标志
if (SET == can0_receive_flag) {
// printf("can0 %X receive data,length%d:", receive_message.rx_efid,
// receive_message.rx_dlen);
// for (int i = 0; i < receive_message.rx_dlen; i++) {
// printf(" 0x%02x", receive_message.rx_data[i]);
// }
// printf("\n");
if (receive_message.rx_efid == CANFD_OTA_DATA_ID or
receive_message.rx_efid == CANFD_OTA_REQ_ID) {
ota.handleOTAMessage(receive_message.rx_efid,
receive_message.rx_data,
receive_message.rx_dlen);
} else {
#if CAN_DEBUG
printf("Unknown CAN ID: %X\n", receive_message.rx_efid);
#endif
}
can0_receive_flag = RESET;
@@ -233,6 +221,11 @@ u8 CAN_transmiter::sendDATA_ACK(u32 packet_num, u8 *data) { // 握手的时候
return CANFD_AsyncSend(CANFD_OTA_ACK_ID, 6, transmit_data);
}
u8 CAN_transmiter::sendBackup() { // 握手的时候
return CANFD_AsyncSend(CANFD_OTA_ACK_ID, 0, transmit_data);
}
u8 CAN_transmiter::sendDATA_ACK(u32 packet_num,
bool if_success) { // 发送数据的时候
memset(transmit_data, 0, 4);
@@ -361,7 +354,6 @@ u8 CAN_transmiter::CANFD_AsyncSend(u32 id, u8 length, u8 *data) {
} else {
#if CAN_DEBUG
printf("CANFD data length error\r\n");
#endif
return 0;
}
+2 -1
View File
@@ -38,7 +38,8 @@ class CAN_transmiter {
void communication_check(); // 通信检查
u8 CANFD_AsyncSend(u32 ID, u8 length, u8 *data); // CANFD异步发送(使用DMA)
u8 sendDATA_ACK(u32 packet_num, bool if_success);
u8 sendDATA_ACK(u32 packet_num, u8* data); // 恢复原函数签名
u8 sendDATA_ACK(u32 packet_num, u8 *data); // 恢复原函数签名
u8 sendBackup();
};
#ifdef __cplusplus
+3 -3
View File
@@ -16,8 +16,6 @@ void BootloaderSystem::initHardware() {
systick_config(); // 系统时钟初始化
USART0_init(); // 调试串口初始化
// rcu_periph_clock_enable(RCU_CRC); // 使能CRC外设时钟
// crc_deinit(); // 初始化CRC模块
CAN0_transmiter.init();
}
@@ -46,10 +44,12 @@ void BootloaderSystem::run() {
u32 back_check = *flash_ptr;
if (back_check == OTA_AVAL and
back_aval == OTA_AVAL) { // backup已确认且激活,复制到主APP区域
printf("OTA Mode3\r\n");
CAN0_transmiter.sendBackup();
move_app_data(); // 恢复BACKUP
ota.jumpToApplication(); // 跳转到APP
} else { // backup无效,进入OTA模式
printf("OTA Mode2\r\n");
printf("OTA Mode4\r\n");
// OTA模式
while (1) {
CAN0_transmiter.communication_check();
+25 -15
View File
@@ -108,7 +108,7 @@ void OTAHandler::process() {
delay_1ms(10);
return;
} else {
delay_1ms(1);
delay_1us(100);
ota_time++;
}
@@ -126,8 +126,8 @@ void OTAHandler::process() {
if (if_checked == OTA_AVAL and if_aval == OTA_AVAL) {
OTA_SET(n_APP_LATEST_AVAL_ADDR,
OTA_AVAL); // 实际可用,设置APP为启用
jumpToApplication();
}
jumpToApplication();
}
}
bool validateApplication() {
@@ -218,7 +218,11 @@ void OTAHandler::jumpToApplication() {
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();
@@ -234,6 +238,9 @@ void OTAHandler::jumpToApplication() {
* @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();
@@ -338,6 +345,10 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
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前验证数据
@@ -347,6 +358,7 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
OTA_PACKET_SIZE);
} else {
ota_error = OTA_ERROR_INVALID_SIZE;
ota_state = OTA_STATE_IDLE;
send_error_frame(OTA_ERROR_INVALID_SIZE);
}
}
@@ -374,11 +386,13 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
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);
@@ -393,6 +407,7 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
} 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) {
@@ -471,7 +486,7 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
// 验证失败 - 可能密钥错误或攻击
ota_error = OTA_ERROR_INVALID_KEY;
send_error_frame(OTA_ERROR_INVALID_KEY); // 验证失败
// reset_ota_state();
ota_state = OTA_STATE_IDLE;
return;
}
@@ -484,6 +499,7 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
} else {
// 其他握手异常
ota_error = OTA_ERROR_INVALID_HANDSHAKE;
ota_state = OTA_STATE_IDLE;
send_error_frame(OTA_ERROR_INVALID_HANDSHAKE);
return;
}
@@ -569,17 +585,16 @@ fmc_state_enum move_app_data() {
// 复制数据 - 按字(32位)进行复制以提高效率
uint32_t offset = 0;
uint32_t write_count = 0; // 记录实际写入的字数
const uint32_t *src_ptr = (const uint32_t *)APPLATEST_START_ADDR;
uint32_t *dst_ptr = (uint32_t *)APPLATEST_START_ADDR;
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);
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];
uint32_t src_data = src_ptr[offset / 4]; // 从备份区域读取数据
// 检查源地址是否为有效的Flash数据(非0xFFFFFFFF表示有数据)
if (src_data != 0xFFFFFFFF) {
@@ -588,7 +603,7 @@ fmc_state_enum move_app_data() {
FMC_FLAG_PGERR);
fmc_status =
fmc_word_program(APPLATEST_START_ADDR + offset, src_data);
fmc_word_program(APPLATEST_START_ADDR + offset, src_data); // 写入到最新APP区域
// 检查写入操作是否成功
if (fmc_status != FMC_READY) {
@@ -604,11 +619,6 @@ fmc_state_enum move_app_data() {
write_count++;
}
offset += 4;
// 每写入一定数量的数据后,喂狗一次
if ((offset % 4096) == 0) { // 每4KB喂狗一次
fwdgt_counter_reload();
}
}
fmc_lock();
@@ -710,4 +720,4 @@ void calculate_crc32_with_key(const uint8_t *key, const uint8_t *data,
output[1] = (uint8_t)(crc >> 8);
output[2] = (uint8_t)(crc >> 16);
output[3] = (uint8_t)(crc >> 24);
}
}
+11 -11
View File
@@ -10,20 +10,20 @@
class OTAHandler {
public:
u32 ota_stateota_time;
uint32_t received_size;
uint32_t expected_size;
u32 received_size;
u32 expected_size;
void init();
void process();
bool isActive() const { return ota_state; }
void handleOTAMessage(uint32_t id, uint8_t *data, uint8_t len);
void handleOTAMessage(u32 id, u8 *data, u8 len);
void jumpToApplication();
private:
u16 ota_time;
u32 ota_time;
void eraseApplicationArea();
void writeApplicationData(uint32_t offset, uint8_t *data, uint32_t size);
void writeApplicationData(u32 offset, u8 *data, u32 size);
bool verifyApplicationData(u32 offset, u8 *data, u32 size);
typedef enum {
OTA_STATE_IDLE = 0,
@@ -44,18 +44,18 @@ class OTAHandler {
OTA_ERROR_INVALID_SIZE
} ota_error_t;
uint8_t device_uid[12]; // 从GD32 UID寄存器读取
uint8_t current_K_session[16];
uint8_t nonce_server[16];
u8 device_uid[12]; // 从GD32 UID寄存器读取
u8 current_K_session[16];
u8 nonce_server[16];
aes128_context aes_ctx; // AES上下文
ota_state_t ota_state = OTA_STATE_IDLE;
ota_error_t ota_error = OTA_ERROR_NONE;
};
void getDeviceSerialNumber(uint8_t *buffer);
void calculate_crc32_with_key(const uint8_t *key, const uint8_t *data,
void getDeviceSerialNumber(u8 *buffer);
void calculate_crc32_with_key(const u8 *key, const u8 *data,
u8 *output);
void send_error_frame(uint8_t error);
void send_error_frame(u8 error);
bool validateApplication();
fmc_state_enum move_app_data();
+1 -1
View File
@@ -54,7 +54,7 @@ constexpr uint8_t K_master[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB,
0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98,
0x76, 0x54, 0x32, 0x10}; // 预置主密钥
// 其他
constexpr u32 OTA_TIMEOUT = 10000;
constexpr u32 OTA_TIMEOUT = 100000;
constexpr u8 SIZE_U32 = sizeof(uint32_t);
constexpr u8 SIZE_FLOAT = sizeof(float);
#endif
+18
View File
@@ -56,6 +56,24 @@ void systick_config(void) {
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/*!
\brief delay a time in microseconds
\param[in] count: count in microseconds
\param[out] none
\retval none
*/
void delay_1us(uint32_t count) {
/* 计算循环次数以实现微秒延时
假设CPU每执行一条nop指令需要1个时钟周期
根据系统时钟频率计算需要的循环次数 */
uint32_t cycles = (SystemCoreClock / 4000000UL) * count; // 每微秒的时钟周期数
/* 循环减去执行指令所需的周期数 */
for(uint32_t i = 0; i < cycles; i++) {
__NOP(); // 空操作指令
}
}
/*!
\brief delay a time in milliseconds
\param[in] count: count in milliseconds
+2
View File
@@ -44,6 +44,8 @@ extern "C" {
void systick_config(void);
/* delay a time in milliseconds */
void delay_1ms(uint32_t count);
/* delay a time in microseconds */
void delay_1us(uint32_t count);
/* delay a time in seconds */
void delay_1s(uint32_t count);
/* delay decrement */