refactor(ota): 移除ESP32 OTA架构中的高危设计问题并优化状态管理

- 移除OtaRelay职责过载问题,将状态查询统一收口到OtaCoordinator::getSnapshot()
- 新增OtaSnapshot结构体,一次性获取完整的OTA系统状态快照,避免分散读取
- 将GD32 APP探测逻辑从system_status_handler中分离,提供独立的/system/probe端点
- 修复并发安全隐患,确保processEvent()读取relayState时持有锁保护
- 优化SPI通信相关代码结构,提升系统稳定性

BREAKING CHANGE: 移除了原有的分散状态查询接口,统一使用快照方式获取状态
This commit is contained in:
小龙虾
2026-06-23 00:05:56 +08:00
parent 1491e9a3de
commit 7a41eac526
11 changed files with 236 additions and 189 deletions
+37
View File
@@ -123,6 +123,18 @@ void OtaRelay::getGd32Version(gd32_version_t *out)
*out = gd32Version;
}
RelaySnapshot OtaRelay::getSnapshot()
{
StateLockGuard lock;
RelaySnapshot s;
s.state = relayState;
s.seq = relaySeq;
s.total_packets = relayTotalPackets;
s.gd32_app_alive = gd32AppAlive;
s.version = gd32Version;
return s;
}
void OtaRelay::setState(relay_state_t s)
{
StateLockGuard lock;
@@ -1241,6 +1253,31 @@ void OtaRelay::taskEntry(void *pvParameters)
return;
}
// ★ 启动时初始 GD32 探测:读取 GD32 APP 版本号与存活状态
// GD32 APP 启动需要一定时间,给其 3 秒准备窗口后发起探测
{
DEBUG_INFO("OTA", "启动初始 GD32 探测...");
vTaskDelay(pdMS_TO_TICKS(3000)); // 等待 GD32 APP 就绪
uint32_t uptime = 0;
gd32_version_t ping_ver = {};
esp_err_t ping_err = SpiMaster::instance().appPing(2000, &uptime, &ping_ver);
if (ping_err == ESP_OK) {
StateLockGuard lock;
gd32AppAlive = true;
gd32Version = ping_ver;
DEBUG_INFO("OTA", "启动 GD32 探测成功: uptime=%" PRIu32 "s, "
"APP=v%d.%d.%d.%d, BOOT=v%d.%d.%d.%d",
uptime,
ping_ver.app_major, ping_ver.app_minor,
ping_ver.app_patch, ping_ver.app_build,
ping_ver.boot_major, ping_ver.boot_minor,
ping_ver.boot_patch, ping_ver.boot_build);
} else {
DEBUG_WARN("OTA", "启动 GD32 探测失败: %s (GD32 可能未就绪)",
esp_err_to_name(ping_err));
}
}
while (1) {
uint32_t msg = 0;
BaseType_t ret = xQueueReceive(dispatchQueue, &msg, portMAX_DELAY);
+22
View File
@@ -82,6 +82,22 @@ public:
virtual void onRelayComplete(bool success) = 0;
};
// ============================================================
// 中继进度快照(一次锁保护读取,消除逐 getter 不一致)
// ============================================================
/**
* @brief GD32 中继进度只读快照。
* 由 OtaRelay::getSnapshot() 在单次 StateLockGuard 下填充,
* 供 OtaCoordinator::getSnapshot() 组装完整系统快照。
*/
struct RelaySnapshot {
relay_state_t state = RELAY_IDLE; ///< 当前中继状态机状态
uint32_t seq = 0; ///< 当前中继包序号
uint32_t total_packets = 0; ///< 本次中继总包数
bool gd32_app_alive = false; ///< GD32 APP 存活标志
gd32_version_t version = {}; ///< GD32 固件版本
};
class OtaRelay {
public:
/**
@@ -138,6 +154,12 @@ public:
* @param out 输出版本信息结构体指针。
*/
static void getGd32Version(gd32_version_t *out);
/**
* @brief 一次性读取所有中继状态字段(单次锁保护)。
* 消除逐 getter 调用之间 relay task 更新状态导致的不一致。
* @return 中继进度快照。
*/
static RelaySnapshot getSnapshot();
/**
* @brief 设置中继状态.
* @param s 目标状态。