feat(ota): 添加OTA回滚保护和固件完整性校验功能

- 启用CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE和CONFIG_APP_ROLLBACK_ENABLE配置选项
- 在main.cpp中添加esp_ota_mark_app_valid_cancel_rollback()调用,防止意外回滚
- 实现SHA-256固件完整性校验,包括计算、存储和验证功能
- 添加ota_mutex.h头文件用于ESP32 OTA全局互斥锁管理

feat(health_monitor): 实现线程安全的健康状态管理

- 将HealthMonitor类的健康状态改为私有成员并通过mutex保护
- 添加getState()和setState()方法提供线程安全的状态访问
- 修复多任务并发访问健康状态时的竞争条件问题

feat(ota_relay): 增强中继模块的线程安全性和可靠性

- 为OtaRelay类添加静态mutex保护状态变量访问
- 实现StateLockGuard RAII锁管理器确保异常安全
- 添加全局超时机制防止OTA过程无限等待
- 改进flash写入逻辑支持非4字节对齐数据处理

refactor(app_config): 更新版本信息和配置常量

- 更新BUILD_TIME至最新编译时间
- 更新GIT_HASH至最新提交
- 添加BLE_OTA_CTRL_VERIFY_SHA256命令常量定义
This commit is contained in:
小龙虾
2026-06-14 17:10:24 +08:00
parent 6a6bc9dab4
commit 2caf10b9de
26 changed files with 5221 additions and 949 deletions
+60 -37
View File
@@ -3,6 +3,8 @@
* 包含:健康状态管理 + WiFi RSSI 监控 + 温度监控
*
* 所有功能封装为 HealthMonitor 类方法。
* 所有对 m_healthState / m_lastTemperature / m_lastWifiRssi 的访问
* 均通过 m_mutex 保护,消除跨任务竞态。
*/
#include <stdio.h>
#include <string.h>
@@ -18,11 +20,6 @@
#include "debug_log.h"
#include "server/wifi_ota.h"
// ============================================================
// 静态成员
// ============================================================
health_state_t HealthMonitor::healthState = SYS_NORMAL;
// ============================================================
// 单例
// ============================================================
@@ -44,36 +41,54 @@ void HealthMonitor::init()
}
// ============================================================
// 获取当前健康状态
// 线程安全的健康状态读写
// ============================================================
health_state_t HealthMonitor::getState()
{
if (m_mutex) xSemaphoreTake(m_mutex, portMAX_DELAY);
health_state_t s = m_healthState;
if (m_mutex) xSemaphoreGive(m_mutex);
return s;
}
void HealthMonitor::setState(health_state_t newState)
{
if (m_mutex) xSemaphoreTake(m_mutex, portMAX_DELAY);
m_healthState = newState;
if (m_mutex) xSemaphoreGive(m_mutex);
}
// ============================================================
// 获取当前健康状态(public 接口)
// ============================================================
health_state_t HealthMonitor::getCurrent()
{
health_state_t state;
if (m_mutex) {
xSemaphoreTake(m_mutex, portMAX_DELAY);
}
state = healthState;
if (m_mutex) {
xSemaphoreGive(m_mutex);
}
return state;
return getState();
}
float HealthMonitor::getLastTemperature()
{
return m_lastTemperature;
if (m_mutex) xSemaphoreTake(m_mutex, portMAX_DELAY);
float t = m_lastTemperature;
if (m_mutex) xSemaphoreGive(m_mutex);
return t;
}
bool HealthMonitor::getLastWifiRssi(int8_t *out_rssi, uint32_t *out_age_ms)
{
if (m_lastWifiRssiMs <= 0) {
if (m_mutex) xSemaphoreTake(m_mutex, portMAX_DELAY);
int64_t lastMs = m_lastWifiRssiMs;
int8_t rssi = m_lastWifiRssi;
if (m_mutex) xSemaphoreGive(m_mutex);
if (lastMs <= 0) {
return false;
}
int64_t now_ms = esp_timer_get_time() / 1000;
uint32_t age_ms = (now_ms > m_lastWifiRssiMs) ? (uint32_t)(now_ms - m_lastWifiRssiMs) : 0;
uint32_t age_ms = (now_ms > lastMs) ? (uint32_t)(now_ms - lastMs) : 0;
if (out_rssi) *out_rssi = m_lastWifiRssi;
if (out_rssi) *out_rssi = rssi;
if (out_age_ms) *out_age_ms = age_ms;
return true;
}
@@ -91,15 +106,18 @@ void HealthMonitor::tempMonitorCallback(void *arg)
return;
}
if (self.m_mutex) xSemaphoreTake(self.m_mutex, portMAX_DELAY);
self.m_lastTemperature = temp;
if (self.m_mutex) xSemaphoreGive(self.m_mutex);
if (temp >= TEMP_CRITICAL) {
healthState = SYS_SAFE_SHUTDOWN;
self.setState(SYS_SAFE_SHUTDOWN);
DEBUG_ERR("TEMP", "!!! 危险 !!! 温度 %.1f°C >= %d°C,触发安全关机", temp, TEMP_CRITICAL);
DEBUG_ERR("TEMP", "健康状态变更为: SYS_SAFE_SHUTDOWN");
} else if (temp >= TEMP_WARNING) {
if (healthState < SYS_WARNING) {
healthState = SYS_WARNING;
health_state_t cur = self.getState();
if (cur < SYS_WARNING) {
self.setState(SYS_WARNING);
DEBUG_WARN("TEMP", "警告: 温度 %.1f°C >= %d°C", temp, TEMP_WARNING);
DEBUG_WARN("TEMP", "健康状态变更为: SYS_WARNING");
}
@@ -144,8 +162,9 @@ void HealthMonitor::taskEntry(void *pvParameters)
if (free_heap < HEAP_WARNING_MIN) {
DEBUG_WARN("MON", "堆内存不足: %lu < %lu", free_heap, HEAP_WARNING_MIN);
}
if (healthState >= SYS_CRITICAL) {
DEBUG_ERR("MON", "健康状态危险: %d", healthState);
health_state_t cur = self.getState();
if (cur >= SYS_CRITICAL) {
DEBUG_ERR("MON", "健康状态危险: %d", cur);
}
vTaskDelay(pdMS_TO_TICKS(5000));
}
@@ -165,14 +184,15 @@ void HealthMonitor::logEvent(const char *event, int value)
health_status_t HealthMonitor::checkBeforeOta()
{
health_status_t status = HEALTH_MON_OK;
health_state_t cur = getState();
if (healthState >= SYS_SAFE_SHUTDOWN) {
if (cur >= SYS_SAFE_SHUTDOWN) {
DEBUG_WARN("HEALTH", "OTA 前检查: SYS_SAFE_SHUTDOWN,禁止传输");
return HEALTH_MON_SHUTDOWN;
} else if (healthState >= SYS_CRITICAL) {
} else if (cur >= SYS_CRITICAL) {
DEBUG_WARN("HEALTH", "OTA 前检查: SYS_CRITICAL,禁止传输");
return HEALTH_MON_CRITICAL;
} else if (healthState >= SYS_WARNING) {
} else if (cur >= SYS_WARNING) {
status = HEALTH_MON_WARNING;
DEBUG_WARN("HEALTH", "OTA 前检查: SYS_WARNING,继续传输但需注意");
}
@@ -210,18 +230,19 @@ health_status_t HealthMonitor::checkBeforeOta()
health_status_t HealthMonitor::checkBeforeOtaRelay()
{
health_status_t status = HEALTH_MON_OK;
health_state_t cur = getState();
if (healthState >= SYS_SAFE_SHUTDOWN) {
if (cur >= SYS_SAFE_SHUTDOWN) {
DEBUG_WARN("HEALTH", "OTA 中继检查: SYS_SAFE_SHUTDOWN,禁止传输");
return HEALTH_MON_SHUTDOWN;
} else if (healthState >= SYS_CRITICAL) {
} else if (cur >= SYS_CRITICAL) {
/* SYS_CRITICAL 可能是由 WiFi RSSI 过低导致的,
* 但 SPI 中继阶段不依赖 WiFi,只检查温度/硬件等本地状态。
* 温度达到 TEMP_CRITICAL(100°C) 时 g_health_state 会被设为
* 温度达到 TEMP_CRITICAL(100°C) 时 m_healthState 会被设为
* SYS_SAFE_SHUTDOWN,在上面的分支已经拦截。
* 所以 SYS_CRITICAL 在中继阶段只可能是 WiFi 导致的,允许继续。 */
DEBUG_WARN("HEALTH", "OTA 中继检查: SYS_CRITICAL (WiFi 相关),SPI 中继允许继续");
} else if (healthState >= SYS_WARNING) {
} else if (cur >= SYS_WARNING) {
status = HEALTH_MON_WARNING;
DEBUG_WARN("HEALTH", "OTA 中继检查: SYS_WARNING,继续传输");
}
@@ -243,24 +264,26 @@ health_status_t HealthMonitor::checkBeforeOtaRelay()
health_status_t HealthMonitor::updateFromWifiRssi(int8_t rssi)
{
if (rssi < WIFI_RSSI_CRITICAL) {
healthState = SYS_CRITICAL;
setState(SYS_CRITICAL);
DEBUG_WARN("HEALTH", "WiFi RSSI 危险: %d dBm < %d dBm", rssi, WIFI_RSSI_CRITICAL);
logEvent("WIFI危险", rssi);
return HEALTH_MON_CRITICAL;
} else if (rssi < WIFI_RSSI_NORMAL) {
if (healthState < SYS_WARNING) {
healthState = SYS_WARNING;
health_state_t cur = getState();
if (cur < SYS_WARNING) {
setState(SYS_WARNING);
DEBUG_WARN("HEALTH", "WiFi RSSI 警告: %d dBm < %d dBm", rssi, WIFI_RSSI_NORMAL);
logEvent("WIFI警告", rssi);
}
return HEALTH_MON_WARNING;
}
if (healthState == SYS_WARNING && rssi >= WIFI_RSSI_NORMAL) {
healthState = SYS_NORMAL;
health_state_t cur = getState();
if (cur == SYS_WARNING && rssi >= WIFI_RSSI_NORMAL) {
setState(SYS_NORMAL);
DEBUG_INFO("HEALTH", "WiFi RSSI 恢复: %d dBm >= %d dBm", rssi, WIFI_RSSI_NORMAL);
logEvent("WIFI恢复", rssi);
}
return HEALTH_MON_OK;
}
}
+8 -4
View File
@@ -54,7 +54,7 @@ public:
/** @brief 记录一条健康事件日志。 */
void logEvent(const char *event, int value);
/** @brief 获取当前系统健康状态。 */
/** @brief 获取当前系统健康状态(线程安全)。 */
health_state_t getCurrent();
/** @brief 根据 WiFi RSSI 更新健康状态。 */
@@ -66,10 +66,13 @@ public:
/** @brief 获取最近一次 WiFi RSSI 及其年龄。 */
bool getLastWifiRssi(int8_t *out_rssi, uint32_t *out_age_ms);
/** @brief 全局健康状态(public,供外部读取)。 */
static health_state_t healthState;
private:
/** @brief 加锁读取健康状态。 */
health_state_t getState();
/** @brief 加锁设置健康状态。 */
void setState(health_state_t newState);
HealthMonitor() = default;
~HealthMonitor() = default;
HealthMonitor(const HealthMonitor&) = delete;
@@ -77,6 +80,7 @@ private:
SemaphoreHandle_t m_mutex = NULL;
temperature_sensor_handle_t m_tempHandle = NULL;
health_state_t m_healthState = SYS_NORMAL;
float m_lastTemperature = 0.0f;
int8_t m_lastWifiRssi = -127;
int64_t m_lastWifiRssiMs = 0;