fix(ota): 修复OtaCoordinator互斥锁死锁和SPI appPing首字节丢失
- OtaCoordinator lock/unlock: 移除共享 m_locked 标志,改为传参传递 take 结果,消除多任务并发 lock() 超时覆盖持锁状态导致 mutex 永久死锁的问题 - SPI appPing: 发送帧填充至 16 字节防止首字节丢失,增大轮询间隔至 10ms, 增大接收缓冲区避免字节偏移解析失败 - SPI init: 先创建 mutex 再使用 LockGuard,消除竞态窗口 - 压制 WiFi 框架 INFO 日志 (pp/net80211/wifi/wifi_init),减少启动打印 - 降级 7 条调试日志为 DBG 级别(UART0 初始化、冷启动缓存清理、互斥锁/重连 任务/回调/netif 创建) - GD32 版本号读取增加 5 次重试上限和 OTA 繁忙时跳过逻辑 - 移除 forwardFirmware 中已过时注释
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_http_server.h"
|
||||
@@ -1164,21 +1165,37 @@ static esp_err_t system_status_handler(httpd_req_t *req)
|
||||
gd32_version_t pingVer = {};
|
||||
OtaRelay::getGd32Version(&pingVer);
|
||||
|
||||
/* 若尚无 GD32 版本信息且 OTA 中继空闲,尝试一次 SPI PING 获取 */
|
||||
if (pingVer.app_major == 0 &&
|
||||
/* 若尚无 GD32 版本信息且 OTA 中继空闲,尝试 SPI PING 获取(最多 5 次) */
|
||||
// ★ 修复:OTA 活跃期间(存储/中继/ESP32 OTA)跳过 appPing(),
|
||||
// 避免 HTTP 任务长期持有 SPI mutex 与 relay 任务争用,
|
||||
// 导致优先级继承异常 → vTaskPriorityDisinheritAfterTimeout assert。
|
||||
ota_system_state_t curSysState = OtaCoordinator::instance().getSystemState();
|
||||
bool ota_busy = (curSysState == OTA_SYS_GD32_STORING ||
|
||||
curSysState == OTA_SYS_GD32_RELAYING ||
|
||||
curSysState == OTA_SYS_ESP32_RECEIVING ||
|
||||
curSysState == OTA_SYS_ESP32_FINALIZING ||
|
||||
curSysState == OTA_SYS_ESP32_REBOOTING);
|
||||
if (!ota_busy &&
|
||||
pingVer.app_major == 0 &&
|
||||
pingVer.boot_major == 0 &&
|
||||
OtaRelay::getState() == RELAY_IDLE) {
|
||||
static uint32_t last_ping_ms = 0;
|
||||
static uint8_t ping_attempts = 0;
|
||||
uint32_t now_ms = (uint32_t)(esp_timer_get_time() / 1000);
|
||||
if (now_ms - last_ping_ms > 5000) { /* 5 秒节流 */
|
||||
if (ping_attempts < 5 && now_ms - last_ping_ms > 5000) { /* 5 秒节流 */
|
||||
last_ping_ms = now_ms;
|
||||
++ping_attempts;
|
||||
uint32_t uptime = 0;
|
||||
gd32_version_t ver = {};
|
||||
if (SpiMaster::instance().appPing(500, &uptime, &ver) == ESP_OK) {
|
||||
OtaRelay::setGd32AppAlive(true);
|
||||
OtaRelay::setGd32Version(ver);
|
||||
ping_attempts = 0; /* 成功后重置,允许后续更新 */
|
||||
} else {
|
||||
OtaRelay::setGd32AppAlive(false);
|
||||
if (ping_attempts >= 5) {
|
||||
DEBUG_WARN("STATUS", "GD32 版本号读取失败,已达最大重试次数 (5),停止尝试");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1502,7 +1519,7 @@ bool WifiOta::earlyInit()
|
||||
nvs_erase_all(nvs_handle);
|
||||
nvs_commit(nvs_handle);
|
||||
nvs_close(nvs_handle);
|
||||
DEBUG_INFO("WIFI", "冷启动: 已清除 WiFi NVS 缓存 (nvs.net80211)");
|
||||
DEBUG_DBG("WIFI", "冷启动: 已清除 WiFi NVS 缓存 (nvs.net80211)");
|
||||
} else {
|
||||
DEBUG_INFO("WIFI", "冷启动: 无 WiFi NVS 缓存分区,跳过清除");
|
||||
}
|
||||
@@ -1512,7 +1529,7 @@ bool WifiOta::earlyInit()
|
||||
nvs_erase_all(nvs_handle);
|
||||
nvs_commit(nvs_handle);
|
||||
nvs_close(nvs_handle);
|
||||
DEBUG_INFO("WIFI", "冷启动: 已清除 PHY 校准缓存,将重新校准");
|
||||
DEBUG_DBG("WIFI", "冷启动: 已清除 PHY 校准缓存,将重新校准");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1522,7 +1539,7 @@ bool WifiOta::earlyInit()
|
||||
if (mtx) {
|
||||
// 通过临时获取再赋值(私有成员在同类内可访问)
|
||||
WifiOta::instance().m_stateMutex = mtx;
|
||||
DEBUG_INFO("WIFI", "状态互斥锁已创建");
|
||||
DEBUG_DBG("WIFI", "状态互斥锁已创建");
|
||||
} else {
|
||||
DEBUG_ERR("WIFI", "创建状态互斥锁失败");
|
||||
}
|
||||
@@ -1542,14 +1559,14 @@ bool WifiOta::earlyInit()
|
||||
if (ret != pdPASS) {
|
||||
DEBUG_ERR("WIFI", "创建重连任务失败");
|
||||
} else {
|
||||
DEBUG_INFO("WIFI", "WiFi 重连任务已创建");
|
||||
DEBUG_DBG("WIFI", "WiFi 重连任务已创建");
|
||||
}
|
||||
}
|
||||
|
||||
// 注册 WiFi/IP 事件回调(必须在 esp_wifi_init 之前)
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &WifiOta::wifiEventHandler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &WifiOta::wifiEventHandler, NULL));
|
||||
DEBUG_INFO("WIFI", "WiFi/IP 事件回调已注册");
|
||||
DEBUG_DBG("WIFI", "WiFi/IP 事件回调已注册");
|
||||
|
||||
esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
if (sta_netif == NULL) {
|
||||
@@ -1557,12 +1574,18 @@ bool WifiOta::earlyInit()
|
||||
if (sta_netif == NULL) {
|
||||
DEBUG_ERR("WIFI", "创建 STA netif 失败");
|
||||
} else {
|
||||
DEBUG_INFO("WIFI", "STA netif 已创建");
|
||||
DEBUG_DBG("WIFI", "STA netif 已创建");
|
||||
}
|
||||
} else {
|
||||
DEBUG_INFO("WIFI", "STA netif 已存在,跳过创建");
|
||||
}
|
||||
|
||||
// ★ 压制 WiFi 框架内部 INFO 日志(pp/net80211/wifi/wifi_init 等 tag 大量启动打印)
|
||||
esp_log_level_set("wifi", ESP_LOG_WARN);
|
||||
esp_log_level_set("wifi_init", ESP_LOG_WARN);
|
||||
esp_log_level_set("pp", ESP_LOG_WARN);
|
||||
esp_log_level_set("net80211", ESP_LOG_WARN);
|
||||
|
||||
wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&wifi_cfg));
|
||||
DEBUG_INFO("WIFI", "WiFi driver 初始化成功");
|
||||
|
||||
Reference in New Issue
Block a user