基础响应功能的实现
This commit is contained in:
+82
-46
@@ -1,31 +1,47 @@
|
||||
#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
|
||||
|
||||
OTAHandler::OTAHandler() : ota_active(false), received_size(0) {}
|
||||
|
||||
void OTAHandler::init() {
|
||||
// 初始化CANFD接收中断
|
||||
nvic_irq_enable(CAN0_RX0_IRQn, 1, 1);
|
||||
}
|
||||
void OTAHandler::init() {}
|
||||
|
||||
void OTAHandler::process() {
|
||||
if (!ota_active)
|
||||
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模式
|
||||
// 检查是否超时(例如:10秒无数据则退出OTA模式)
|
||||
if (ota_time > 10000) { // 10秒超时(10000 x 1ms)
|
||||
ota_time = 0;
|
||||
ota_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool OTAHandler::validateApplication() {
|
||||
uint32_t *app_vector = (uint32_t *)APP_START_ADDR;
|
||||
uint32_t stack_ptr = app_vector[0];
|
||||
uint32_t reset_handler = app_vector[1];
|
||||
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) &&
|
||||
@@ -34,45 +50,58 @@ bool OTAHandler::validateApplication() {
|
||||
}
|
||||
|
||||
void OTAHandler::jumpToApplication() {
|
||||
if (!validateApplication()) {
|
||||
// 无效APP,停留在bootloader
|
||||
return;
|
||||
}
|
||||
|
||||
// 关闭所有中断
|
||||
__disable_irq();
|
||||
|
||||
// 设置主栈指针
|
||||
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;
|
||||
|
||||
// 跳转
|
||||
app_entry();
|
||||
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 (uint32_t addr = APP_START_ADDR; addr < (APP_START_ADDR + APP_MAX_SIZE);
|
||||
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(uint32_t offset, uint8_t *data,
|
||||
uint32_t size) {
|
||||
void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
|
||||
fmc_unlock();
|
||||
uint32_t write_addr = APP_START_ADDR + offset;
|
||||
u32 write_addr = APP_START_ADDR + offset;
|
||||
|
||||
// 32位对齐写入
|
||||
for (uint32_t i = 0; i < size; i += 4) {
|
||||
uint32_t word = 0;
|
||||
for (u32 i = 0; i < size; i += 4) {
|
||||
u32 word = 0;
|
||||
memcpy(&word, &data[i], 4);
|
||||
fmc_word_program(write_addr + i, word);
|
||||
}
|
||||
@@ -80,27 +109,34 @@ void OTAHandler::writeApplicationData(uint32_t offset, uint8_t *data,
|
||||
fmc_lock();
|
||||
}
|
||||
|
||||
void OTAHandler::handleOTAMessage(uint32_t id, uint8_t *data, uint8_t len) {
|
||||
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请求包
|
||||
uint32_t new_size = *(uint32_t *)data;
|
||||
u32 new_size = *(u32 *)data;
|
||||
if (new_size <= APP_MAX_SIZE) {
|
||||
expected_size = new_size;
|
||||
received_size = 0;
|
||||
eraseApplicationArea();
|
||||
// eraseApplicationArea();
|
||||
ota_active = true;
|
||||
sendACK(0xFFFFFFFF); // 确认开始
|
||||
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) {
|
||||
uint32_t packet_num = *(uint32_t *)data;
|
||||
uint32_t offset = packet_num * (len - 4);
|
||||
u32 packet_num = *(u32 *)data;
|
||||
u32 offset = packet_num * (len - 4);
|
||||
|
||||
if (offset < expected_size) {
|
||||
writeApplicationData(offset, &data[4], len - 4);
|
||||
writeApplicationData(offset, &data[4], len - 4); // 写入数据
|
||||
received_size += (len - 4);
|
||||
sendACK(packet_num);
|
||||
sendACK(packet_num); // 确认ACK
|
||||
ota_time = 0; // 重置计时器
|
||||
|
||||
// 检查是否完成
|
||||
if (received_size >= expected_size) {
|
||||
@@ -115,6 +151,6 @@ void OTAHandler::handleOTAMessage(uint32_t id, uint8_t *data, uint8_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
void OTAHandler::sendACK(uint32_t packet_num) {
|
||||
void OTAHandler::sendACK(u32 packet_num) {
|
||||
CAN0_transmiter.sendACK(CANFD_OTA_ACK_ID, packet_num);
|
||||
}
|
||||
Reference in New Issue
Block a user