Files
GD32_BOOT/Robot_V2/sys/OTA.cpp
T
2025-12-27 19:20:23 +08:00

156 lines
3.9 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 "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);
}
#define DEBUG_OTA 1
void OTAHandler::init() {}
void OTAHandler::process() {
if (!ota_active) {
ota_time = 0; // 重置计时器
static u8 zero[1] = {ota_active};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_WAIT_ID, 0, zero);
#ifdef DEBUG_OTA
printf("wait OTA%d\r\n", ota_active);
#endif
delay_1ms(10);
return;
} else {
delay_1ms(1);
ota_time++;
}
// 检查是否超时(例如:10秒无数据则退出OTA模式)
if (ota_time > 10000) { // 10秒超时(10000 x 1ms)
ota_time = 0;
ota_active = false;
}
}
bool OTAHandler::validateApplication() {
u32 *app_vector = (u32 *)APP_START_ADDR;
u32 stack_ptr = app_vector[0];
u32 reset_handler = app_vector[1];
// 简单验证:检查栈指针是否在SRAM范围内
return (stack_ptr >= 0x20000000 && stack_ptr < 0x20008000) &&
(reset_handler >= APP_START_ADDR &&
reset_handler < (APP_START_ADDR + APP_MAX_SIZE));
}
void OTAHandler::jumpToApplication() {
if (!validateApplication()) return;
// 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);
// 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);
// 5. 设置MSP并跳转
uint32_t msp_value = *(__IO uint32_t*)APP_START_ADDR;
__set_MSP(msp_value);
uint32_t reset_handler = *(__IO uint32_t*)(APP_START_ADDR + 4);
typedef void (*AppEntryFunc)(void);
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
// 6. 跳转
app_entry();
}
void OTAHandler::eraseApplicationArea() {
// 擦除APP区域
fmc_unlock();
for (u32 addr = APP_START_ADDR; addr < (APP_START_ADDR + APP_MAX_SIZE);
addr += FMC_PAGE_SIZE) {
fmc_page_erase(addr);
}
fmc_lock();
}
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 word = 0;
memcpy(&word, &data[i], 4);
fmc_word_program(write_addr + i, word);
}
fmc_lock();
}
void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
if (id == CANFD_OTA_REQ_ID) {
#ifdef DEBUG_OTA
printf("req OTA\r\n");
#endif
// OTA请求包
u32 new_size = *(u32 *)data;
if (new_size <= APP_MAX_SIZE) {
expected_size = new_size;
received_size = 0;
// eraseApplicationArea();
ota_active = true;
sendACK(new_size); // 确认开始
#ifdef DEBUG_OTA
printf("start OTA%d\r\n", ota_active);
#endif
}
} else if (id == CANFD_OTA_DATA_ID && ota_active) {
// 数据包格式:[4字节包序号][实际数据]
if (len >= 4) {
u32 packet_num = *(u32 *)data;
u32 offset = packet_num * (len - 4);
if (offset < expected_size) {
writeApplicationData(offset, &data[4], len - 4); // 写入数据
received_size += (len - 4);
sendACK(packet_num); // 确认ACK
ota_time = 0; // 重置计时器
// 检查是否完成
if (received_size >= expected_size) {
ota_active = false;
// 跳转前延时让ACK发出
for (volatile int i = 0; i < 100000; i++)
;
jumpToApplication();
}
}
}
}
}
void OTAHandler::sendACK(u32 packet_num) {
CAN0_transmiter.sendACK(CANFD_OTA_ACK_ID, packet_num);
}