feat(protocol): 更新SPI Link协议至v2版本并优化CAN通信
- 将SPI OTA帧格式升级为SPI Link v2,采用新的帧格式: | SOF0 0xA5 | SOF1 0x5A | VER 0x02 | FLAGS | SESSION 4B LE | TX_SEQ | ACK_SEQ | CREDIT | TYPE | LEN 2B LE | RSV 2B | PAYLOAD | CRC32 4B LE | - 新增V2_OVERHEAD=20字节开销,APP最大payload为236字节,BOOT为108字节 - 修改帧类型定义:ENTER_BOOT从0xB5合并至0xB0,新增CAN业务类型0xC0~C3 - 更新CAN协议文档,支持SPI Link v2-only模式,调整最大业务payload计算 - 扩展0xC1帧功能,支持双向通信和1Hz主动推送ID快照 - 添加0xC3完整ID快照帧类型,包含seq/rx_count等完整字段 - 更新协议文档中的错误码定义和反馈payload格式 refactor(main): 重构主程序入口并添加CAN反馈任务 - 在main.cpp中添加CAN反馈任务,更新启动流程注释 - 创建createCriticalTask辅助函数,统一关键任务创建逻辑 - 调整SPI初始化顺序,确保CAN反馈任务依赖正确 - 优化错误处理机制,关键任务失败时立即重启 - 将GD32版本探测移至ota_relay任务处理 - 更新版本号至0.3.48,调整编译时间和Git哈希 config: 更新SPI和BLE配置参数 - 添加SPI主机相关配置参数,包括CS GPIO、READY GPIO等引脚定义 - 配置SPI缓冲区大小:APP为256字节,BOOT为128字节 - 更新BLE滑动窗口参数,ACK窗口设为32,数据队列深度为72 - 调整SPI工作队列大小至5120字节,增加任务堆栈监控说明
This commit is contained in:
+17
-14
@@ -57,17 +57,12 @@
|
||||
#define BLE_OTA_FINISH_GD32_RELAY_DONE 0x11
|
||||
#define BLE_OTA_FINISH_ABORTED 0x20 // 用户主动中止(BLE 不断开)
|
||||
#define BLE_OTA_FINISH_ERR_FINALIZE 0x81
|
||||
#define BLE_OTA_ACK_WINDOW 32
|
||||
#define BLE_ATT_ERR_OTA_BUSY 0x80 // ESP32 OTA 被其他通道占用
|
||||
#define BLE_OTA_FINISH_ERR_MUTEX 0x83 // 互斥拒绝: OTA 被其他通道占用
|
||||
#define BLE_OTA_FINISH_ERR_GD32_SIZE 0x84 // GD32 固件超出分区大小
|
||||
#define BLE_OTA_FINISH_ERR_SHA_MISMATCH 0x85 // OTA SHA-256 不匹配
|
||||
#define BLE_OTA_FINISH_ERR_GD32_RELAY 0x86 // GD32 SPI OTA 转发失败
|
||||
|
||||
// ── 数据队列:将 OTA 数据处理从 NimBLE host task 卸载到工作线程 ──
|
||||
// 避免 flash 操作(esp_ota_begin / esp_ota_write)阻塞 BLE 协议栈导致连接断开。
|
||||
// 深度略大于窗口:seq=0 整分区预擦期间前端若仍误发,可多扛几批,减少“队列满丢包→重传风暴”。
|
||||
#define BLE_OTA_DATA_QUEUE_LEN (BLE_OTA_ACK_WINDOW * 2 + 8)
|
||||
// BLE_OTA_ACK_WINDOW / BLE_OTA_DATA_QUEUE_LEN / BLE_OTA_REORDER_WINDOW → app_config.h
|
||||
|
||||
struct BleOtaDataBatch {
|
||||
uint8_t *data;
|
||||
@@ -105,6 +100,8 @@ static uint32_t packBleFinishValue(uint16_t session_id, uint16_t code);
|
||||
static void shaBytesToHexUpper(const uint8_t sha[32], char out_hex[65]);
|
||||
static void sendSha256Notify(const uint8_t sha[32], uint16_t session_id);
|
||||
static void esp32_reorder_free();
|
||||
static void ble_ota_session_reset(void);
|
||||
static void ble_ota_restore_wifi_ps(void);
|
||||
static void ble_ota_data_worker_task(void *pvParameters);
|
||||
static void ble_gd32_relay_wait_task(void *pvParameters);
|
||||
|
||||
@@ -182,7 +179,9 @@ static void ble_esp32_finish_and_reboot_task(void *pvParameters)
|
||||
sendFinishEvent(BLE_OTA_FINISH_ERR_FINALIZE,
|
||||
packBleFinishValue(session_id, 1));
|
||||
BleOta::instance().m_esp32RebootPending = false;
|
||||
esp32_reorder_free();
|
||||
// 无效会话:协调器可能仍假占用,走统一会话复位
|
||||
ble_ota_session_reset();
|
||||
ble_ota_restore_wifi_ps();
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
@@ -217,18 +216,22 @@ static void ble_esp32_finish_and_reboot_task(void *pvParameters)
|
||||
DEBUG_ERR(TAG, "[FINISH] SHA-256 不匹配,OTA 已中止");
|
||||
sendFinishEvent(BLE_OTA_FINISH_ERR_SHA_MISMATCH, packBleFinishValue(session_id, 0));
|
||||
BleOta::instance().m_esp32RebootPending = false;
|
||||
// ★ finalize 内部已 abort 并释放 mutex,这里补充通知协调器复位状态机,
|
||||
// 避免 m_sysState 卡在 ESP32_FINALIZING 导致下次 OTA 被假拒绝。
|
||||
OtaCoordinator::instance().abortCurrent();
|
||||
// ★ finalizeForReboot 失败路径已 abortCurrent(协调器→IDLE + core 释放)。
|
||||
// 此处只清 BLE 会话侧 reorder,避免二次 abort 干扰新会话。
|
||||
esp32_reorder_free();
|
||||
BleOta::instance().m_esp32LastSeq = 0xFFFFU;
|
||||
BleOta::instance().m_esp32LastCmd = 0;
|
||||
ble_ota_restore_wifi_ps();
|
||||
} else {
|
||||
DEBUG_ERR(TAG, "[FINISH] OTA 收尾失败: %s", esp_err_to_name(fr.err));
|
||||
sendFinishEvent(BLE_OTA_FINISH_ERR_FINALIZE,
|
||||
packBleFinishValue(session_id, 1));
|
||||
BleOta::instance().m_esp32RebootPending = false;
|
||||
// ★ 同上:finalize 已 abort core,这里通知协调器复位状态机
|
||||
OtaCoordinator::instance().abortCurrent();
|
||||
// ★ 同上:协调器已由 finalizeForReboot 复位,仅清 BLE 侧残留
|
||||
esp32_reorder_free();
|
||||
BleOta::instance().m_esp32LastSeq = 0xFFFFU;
|
||||
BleOta::instance().m_esp32LastCmd = 0;
|
||||
ble_ota_restore_wifi_ps();
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
@@ -1222,7 +1225,7 @@ static bool process_esp32_packet(uint8_t cmd, uint16_t seq, uint32_t total_size,
|
||||
// reorder 可能一次 flush 到下个窗口边界,例如 seq=99 使 expected 直达128;
|
||||
// 此时必须立即 ACK 127,否则后续重复包都不产生 progress,前端只能超时。
|
||||
//
|
||||
// ★ seq=0 强制 ACK:begin 含整分区预擦,可能耗时数秒~数十秒。
|
||||
// ★ seq=0 强制 ACK:begin 后首包需尽快 ACK,前端才能继续窗口。
|
||||
// 前端必须等“首包已落盘”ACK 后再发窗口内其余包,否则队列满丢包→重传极慢。
|
||||
uint32_t completedPackets = (afterReceived + BLE_OTA_CHUNK_PAYLOAD - 1U) /
|
||||
BLE_OTA_CHUNK_PAYLOAD;
|
||||
@@ -1390,7 +1393,7 @@ static bool process_gd32_packet(uint8_t cmd, uint16_t seq, uint32_t total_size,
|
||||
meta.stored_size = stored_size;
|
||||
meta.last_seq = seq;
|
||||
const bool transfer_complete = stored_size >= meta.total_size;
|
||||
// seq=0:prepare 含整分区预擦,写完首包必须 ACK,前端才能继续发后续窗口
|
||||
// seq=0:prepare 后写完首包必须 ACK,前端才能继续发后续窗口
|
||||
const bool checkpoint =
|
||||
(seq == 0U) ||
|
||||
((((uint32_t)seq + 1U) % BLE_OTA_ACK_WINDOW) == 0U) ||
|
||||
|
||||
Reference in New Issue
Block a user