From 8590d327e6d71fbc1bf2d43f37209caa5f5af871 Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Thu, 28 May 2026 23:39:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(ota):=20=E4=BC=98=E5=8C=96=E6=8F=A1?= =?UTF-8?q?=E6=89=8B=E8=AF=B7=E6=B1=82=E5=A4=84=E7=90=86=E5=8F=8AOTA?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 OTA 会话激活状态标志 s_otaSessionActive 及其访问接口 - 在设置传输发送器时激活 OTA 会话状态 - OTAHandler 初始化时显式重置状态机,防止旧状态残留 - 严格区分握手请求 payload,避免 SPI OTA 握手误判状态 - 允许更多 OTA 状态接收握手请求,提升协议容错性 - 非空闲状态拒绝新握手请求并发送等待响应 --- GD32E50X_BOOT/device/SpiOta.cpp | 4 ++++ GD32E50X_BOOT/device/SpiOta.h | 2 ++ GD32E50X_BOOT/sys/OTA.cpp | 18 +++++++++++++----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/GD32E50X_BOOT/device/SpiOta.cpp b/GD32E50X_BOOT/device/SpiOta.cpp index 2028405..a0b6753 100644 --- a/GD32E50X_BOOT/device/SpiOta.cpp +++ b/GD32E50X_BOOT/device/SpiOta.cpp @@ -48,6 +48,7 @@ volatile u16 SpiOta::s_txLen = 0U; volatile bool SpiOta::s_txPending = false; volatile bool SpiOta::s_isrResponded = false; volatile bool SpiOta::s_isrLogPending = false; +volatile bool SpiOta::s_otaSessionActive = false; u8 SpiOta::s_isrLogBuf[kIsrLogBufSize] = {}; u16 SpiOta::s_isrLogLen = 0U; @@ -230,6 +231,7 @@ void SpiOta::isrProcessFrame() { } if (s_otaHandler != nullptr) { + s_otaSessionActive = true; s_otaHandler->setTransportSender(sender); ota_link_msg_type_t msg_type = mapMsgType(frame_type); isrLogFrameEx("[OTA-MSG]", (const u8*)&frame_type, 1); @@ -568,6 +570,8 @@ void SpiOta::feedRxBytes(const u8 *data, u16 len) { bool SpiOta::hasTxFrame() { return s_txPending; } +bool SpiOta::hasActiveSession() { return s_otaSessionActive; } + u16 SpiOta::copyTxFrame(u8 *out, u16 max_len) { if (!out || max_len == 0U) { return 0U; } uint32_t primask = enterCritical(); diff --git a/GD32E50X_BOOT/device/SpiOta.h b/GD32E50X_BOOT/device/SpiOta.h index 8bd1e04..a32d4bc 100644 --- a/GD32E50X_BOOT/device/SpiOta.h +++ b/GD32E50X_BOOT/device/SpiOta.h @@ -43,6 +43,7 @@ public: static void onCsExtiInterrupt(); static void feedRxBytes(const u8 *data, u16 len); static bool hasTxFrame(); + static bool hasActiveSession(); static u16 copyTxFrame(u8 *out, u16 max_len); static void isrProcessFrame(); @@ -59,6 +60,7 @@ public: static volatile bool s_txPending; static volatile bool s_isrResponded; static volatile bool s_isrLogPending; + static volatile bool s_otaSessionActive; static u8 s_isrLogBuf[kIsrLogBufSize]; static u16 s_isrLogLen; diff --git a/GD32E50X_BOOT/sys/OTA.cpp b/GD32E50X_BOOT/sys/OTA.cpp index d18beb7..c13d64c 100644 --- a/GD32E50X_BOOT/sys/OTA.cpp +++ b/GD32E50X_BOOT/sys/OTA.cpp @@ -213,6 +213,8 @@ static inline void send_structured_ack(uint32_t seq_or_flag) { void OTAHandler::init() { /** 默认回包出口先绑定到 CAN。 */ transport_send = ota_can_sender; + /** 显式重置状态机,防止 APP 软跳转后残留旧状态。 */ + resetToIdle(); } /** @@ -478,17 +480,23 @@ void OTAHandler::handleLinkMessage(ota_link_msg_type_t type, u8 *data, u8 len) { } /** * REQ: 握手/开始请求。 - * 空闲态回复 ACK(进入握手流程),非空闲态回复 WAIT。 + * + * 只有 2 字节 payload (0x00 0xAC) 才是真正的握手请求。 + * 16 字节 payload 是协议流程中的 nonce / confirm 数据, + * 需交由后续分支正常处理。 + * + * 这解决了 CAN 总线帧在 SPI OTA 等待窗口内抢先改变 + * ota_state 导致 SPI HANDSHAKE_REQ 收到 WAIT 的问题。 */ - else if (type == OTA_LINK_MSG_REQ) { + else if (type == OTA_LINK_MSG_REQ && len == 2U && data[0] == 0x00U && data[1] == 0xACU) { ota_time = 0; - if (ota_state == OTA_STATE_IDLE) { - /* 空闲态收到 REQ,回复 ACK + echo 0x00 0xAC 表示 BOOT 就绪 */ + if (ota_state <= OTA_STATE_CHECKING_FIRMWARE) { + /* 可重启态:IDLE / WAITING_RANDOM / WAITING_CONFIRM / CHECKING_FIRMWARE */ u8 ack_echo[2] = {0x00, 0xAC}; send_ack_frame(2, ack_echo); ota_state = OTA_STATE_WAITING_RANDOM; } else { - /* 非空闲态收到 REQ,回复 WAIT */ + /* 已接收固件数据,拒绝新 REQ */ u8 wait_hint[1] = {0x01}; send_wait_frame(1, wait_hint); }