feat(main): 将全局函数重构为单例类模式
- 将 debug_log 模块重构为 DebugLog 单例类,封装 UART、UDP 和环形缓冲区日志输出 - 将 health_monitor 模块重构为 HealthMonitor 单例类,统一健康状态管理和监控逻辑 - 更新 main.cpp 中的初始化调用,使用单例实例替代原有全局函数 - 添加健康监控任务作为第四个 FreeRTOS 任务,增强系统监控能力 - 更新固件版本从 0.2.11 到 0.3.0,反映架构重大变更
This commit is contained in:
+92
-129
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
* health_monitor.cpp - 系统健康监控
|
||||
* 包含:健康状态管理 + WiFi RSSI 监控 + 温度监控
|
||||
*
|
||||
* 所有功能封装为 HealthMonitor 类方法。
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -16,207 +18,173 @@
|
||||
#include "debug_log.h"
|
||||
#include "server/wifi_ota.h"
|
||||
|
||||
/** @brief 全局健康状态,受互斥锁保护。 */
|
||||
health_state_t g_health_state = SYS_NORMAL;
|
||||
// ============================================================
|
||||
// 静态成员
|
||||
// ============================================================
|
||||
health_state_t HealthMonitor::healthState = SYS_NORMAL;
|
||||
|
||||
/** @brief 健康状态互斥锁。 */
|
||||
static SemaphoreHandle_t g_health_mutex = NULL;
|
||||
/** @brief 内置温度传感器句柄。 */
|
||||
static temperature_sensor_handle_t s_temp_handle = NULL;
|
||||
/** @brief 最近一次采样的芯片温度(摄氏度)。 */
|
||||
static float s_last_temperature = 0.0f;
|
||||
/** @brief 最近一次健康监控采样得到的 WiFi RSSI。 */
|
||||
static int8_t s_last_wifi_rssi = -127;
|
||||
/** @brief 最近一次 WiFi RSSI 采样时间(毫秒)。 */
|
||||
static int64_t s_last_wifi_rssi_ms = 0;
|
||||
|
||||
// ----------------------------------------
|
||||
// 健康状态管理
|
||||
/**
|
||||
* @brief 初始化健康监控模块,创建互斥锁和基础状态。
|
||||
*/
|
||||
void health_monitor_init(void)
|
||||
// ============================================================
|
||||
// 单例
|
||||
// ============================================================
|
||||
HealthMonitor& HealthMonitor::instance()
|
||||
{
|
||||
/** @brief 健康状态互斥锁。 */
|
||||
g_health_mutex = xSemaphoreCreateMutex();
|
||||
if (g_health_mutex == NULL) {
|
||||
static HealthMonitor inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 初始化
|
||||
// ============================================================
|
||||
void HealthMonitor::init()
|
||||
{
|
||||
m_mutex = xSemaphoreCreateMutex();
|
||||
if (m_mutex == NULL) {
|
||||
DEBUG_ERR("HEALTH", "创建健康状态互斥锁失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前系统健康状态。
|
||||
* @return 当前健康状态枚举值。
|
||||
*/
|
||||
health_state_t health_get_current(void)
|
||||
// ============================================================
|
||||
// 获取当前健康状态
|
||||
// ============================================================
|
||||
health_state_t HealthMonitor::getCurrent()
|
||||
{
|
||||
health_state_t state;
|
||||
if (g_health_mutex) {
|
||||
xSemaphoreTake(g_health_mutex, portMAX_DELAY);
|
||||
if (m_mutex) {
|
||||
xSemaphoreTake(m_mutex, portMAX_DELAY);
|
||||
}
|
||||
state = g_health_state;
|
||||
if (g_health_mutex) {
|
||||
xSemaphoreGive(g_health_mutex);
|
||||
state = healthState;
|
||||
if (m_mutex) {
|
||||
xSemaphoreGive(m_mutex);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回最近一次采样到的芯片温度(摄氏度)。
|
||||
* @return 最近一次温度采样值(摄氏度)。
|
||||
*/
|
||||
float health_get_last_temperature(void)
|
||||
float HealthMonitor::getLastTemperature()
|
||||
{
|
||||
/** @brief 最近一次采样的芯片温度(摄氏度)。 */
|
||||
return s_last_temperature;
|
||||
return m_lastTemperature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取最近一次采样到的 WiFi RSSI 及其年龄。
|
||||
* @param out_rssi 输出 RSSI 指针,可为 NULL。
|
||||
* @param out_age_ms 输出采样距今毫秒数指针,可为 NULL。
|
||||
* @return 有有效采样返回 true,否则返回 false。
|
||||
*/
|
||||
bool health_get_last_wifi_rssi(int8_t *out_rssi, uint32_t *out_age_ms)
|
||||
bool HealthMonitor::getLastWifiRssi(int8_t *out_rssi, uint32_t *out_age_ms)
|
||||
{
|
||||
if (s_last_wifi_rssi_ms <= 0) {
|
||||
if (m_lastWifiRssiMs <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t now_ms = esp_timer_get_time() / 1000;
|
||||
uint32_t age_ms = (now_ms > s_last_wifi_rssi_ms) ? (uint32_t)(now_ms - s_last_wifi_rssi_ms) : 0;
|
||||
uint32_t age_ms = (now_ms > m_lastWifiRssiMs) ? (uint32_t)(now_ms - m_lastWifiRssiMs) : 0;
|
||||
|
||||
if (out_rssi) *out_rssi = s_last_wifi_rssi;
|
||||
if (out_rssi) *out_rssi = m_lastWifiRssi;
|
||||
if (out_age_ms) *out_age_ms = age_ms;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// ============================================================
|
||||
// 温度监控(定时器回调)
|
||||
/**
|
||||
* @brief 温度定时回调,采样并根据阈值更新健康状态。
|
||||
* @param arg
|
||||
*/
|
||||
static void temp_monitor_callback(void *arg)
|
||||
// ============================================================
|
||||
void HealthMonitor::tempMonitorCallback(void *arg)
|
||||
{
|
||||
auto& self = instance();
|
||||
float temp = 0.0f;
|
||||
esp_err_t err = temperature_sensor_get_celsius(s_temp_handle, &temp);
|
||||
esp_err_t err = temperature_sensor_get_celsius(self.m_tempHandle, &temp);
|
||||
if (err != ESP_OK) {
|
||||
DEBUG_WARN("TEMP", "读取温度失败: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
/** @brief 最近一次采样的芯片温度(摄氏度)。 */
|
||||
s_last_temperature = temp;
|
||||
self.m_lastTemperature = temp;
|
||||
|
||||
if (temp >= TEMP_CRITICAL) {
|
||||
/** @brief 全局健康状态,受互斥锁保护。 */
|
||||
g_health_state = SYS_SAFE_SHUTDOWN;
|
||||
healthState = 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 (g_health_state < SYS_WARNING) {
|
||||
/** @brief 全局健康状态,受互斥锁保护。 */
|
||||
g_health_state = SYS_WARNING;
|
||||
if (healthState < SYS_WARNING) {
|
||||
healthState = SYS_WARNING;
|
||||
DEBUG_WARN("TEMP", "警告: 温度 %.1f°C >= %d°C", temp, TEMP_WARNING);
|
||||
DEBUG_WARN("TEMP", "健康状态变更为: SYS_WARNING");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// 温度监控任务入口
|
||||
/**
|
||||
* @brief 启动温度监控定时器,周期性巡检系统健康。
|
||||
* @param pvParameters FreeRTOS 任务参数,未使用。
|
||||
*/
|
||||
void health_monitor_task(void *pvParameters)
|
||||
// ============================================================
|
||||
// FreeRTOS 任务入口
|
||||
// ============================================================
|
||||
void HealthMonitor::taskEntry(void *pvParameters)
|
||||
{
|
||||
auto& self = instance();
|
||||
DEBUG_INFO("MON", "=== 健康监控任务启动 ===");
|
||||
|
||||
temperature_sensor_config_t temp_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(20, 80);
|
||||
esp_err_t err = temperature_sensor_install(&temp_config, &s_temp_handle);
|
||||
esp_err_t err = temperature_sensor_install(&temp_config, &self.m_tempHandle);
|
||||
if (err != ESP_OK) {
|
||||
DEBUG_ERR("MON", "温度传感器初始化失败: %s", esp_err_to_name(err));
|
||||
} else {
|
||||
ESP_ERROR_CHECK(temperature_sensor_enable(s_temp_handle));
|
||||
ESP_ERROR_CHECK(temperature_sensor_enable(self.m_tempHandle));
|
||||
DEBUG_INFO("MON", "温度传感器已启用 (范围 20°C ~ 80°C)");
|
||||
}
|
||||
|
||||
// 定时器,每1秒读取一次温度
|
||||
esp_timer_handle_t temp_timer;
|
||||
esp_timer_create_args_t timer_args = {};
|
||||
timer_args.callback = &temp_monitor_callback;
|
||||
timer_args.callback = &tempMonitorCallback;
|
||||
timer_args.arg = nullptr;
|
||||
timer_args.name = "temp_monitor";
|
||||
timer_args.dispatch_method = ESP_TIMER_TASK;
|
||||
timer_args.skip_unhandled_events = false;
|
||||
esp_timer_create(&timer_args, &temp_timer);
|
||||
esp_timer_start_periodic(temp_timer, 1 * 1000000); // 1秒
|
||||
|
||||
DEBUG_INFO("MON", "温度监控定时器已启动 (间隔 1 秒)");
|
||||
if (esp_timer_create(&timer_args, &temp_timer) == ESP_OK) {
|
||||
esp_timer_start_periodic(temp_timer, 1000000); // 1秒
|
||||
DEBUG_INFO("MON", "温度监控定时器已启动 (1秒间隔)");
|
||||
} else {
|
||||
DEBUG_ERR("MON", "创建温度监控定时器失败");
|
||||
}
|
||||
|
||||
// 保活循环:定时器由 esp_timer 任务驱动,此任务只需保持存活
|
||||
// 状态汇报已由 status_monitor_task 负责,此处只在异常时告警
|
||||
// 周期性巡检
|
||||
while (1) {
|
||||
int8_t rssi = wifi_get_rssi();
|
||||
if (wifi_is_connected() && rssi != -127) {
|
||||
s_last_wifi_rssi = rssi;
|
||||
s_last_wifi_rssi_ms = esp_timer_get_time() / 1000;
|
||||
}
|
||||
|
||||
uint32_t free_heap = esp_get_free_heap_size();
|
||||
if (free_heap < HEAP_WARNING_MIN) {
|
||||
DEBUG_WARN("MON", "空闲堆内存不足: %lu < %d", (unsigned long)free_heap, HEAP_WARNING_MIN);
|
||||
DEBUG_WARN("MON", "堆内存不足: %lu < %lu", free_heap, HEAP_WARNING_MIN);
|
||||
}
|
||||
if (g_health_state >= SYS_CRITICAL) {
|
||||
DEBUG_ERR("MON", "健康状态危险: %d", g_health_state);
|
||||
if (healthState >= SYS_CRITICAL) {
|
||||
DEBUG_ERR("MON", "健康状态危险: %d", healthState);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// ============================================================
|
||||
// 健康事件日志
|
||||
/**
|
||||
* @brief 记录一条健康监控事件日志。
|
||||
* @param event 事件名称字符串。
|
||||
* @param value 事件关联的数值。
|
||||
*/
|
||||
void health_log_event(const char *event, int value)
|
||||
// ============================================================
|
||||
void HealthMonitor::logEvent(const char *event, int value)
|
||||
{
|
||||
DEBUG_INFO("HEALTH", "[健康事件] %s: %d", event, value);
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// OTA 传输前的健康检查
|
||||
/**
|
||||
* @brief OTA 传输前执行健康检查,决定是否允许传输。
|
||||
* @return 健康检查结果,决定是否允许 OTA。
|
||||
*/
|
||||
health_status_t health_check_before_ota(void)
|
||||
// ============================================================
|
||||
// OTA 健康检查
|
||||
// ============================================================
|
||||
health_status_t HealthMonitor::checkBeforeOta()
|
||||
{
|
||||
health_status_t status = HEALTH_MON_OK;
|
||||
|
||||
if (g_health_state >= SYS_SAFE_SHUTDOWN) {
|
||||
if (healthState >= SYS_SAFE_SHUTDOWN) {
|
||||
DEBUG_WARN("HEALTH", "OTA 前检查: SYS_SAFE_SHUTDOWN,禁止传输");
|
||||
return HEALTH_MON_SHUTDOWN;
|
||||
} else if (g_health_state >= SYS_CRITICAL) {
|
||||
} else if (healthState >= SYS_CRITICAL) {
|
||||
DEBUG_WARN("HEALTH", "OTA 前检查: SYS_CRITICAL,禁止传输");
|
||||
return HEALTH_MON_CRITICAL;
|
||||
} else if (g_health_state >= SYS_WARNING) {
|
||||
} else if (healthState >= SYS_WARNING) {
|
||||
status = HEALTH_MON_WARNING;
|
||||
DEBUG_WARN("HEALTH", "OTA 前检查: SYS_WARNING,继续传输但需注意");
|
||||
}
|
||||
|
||||
if (!wifi_is_connected()) {
|
||||
if (!WifiOta::isConnected()) {
|
||||
DEBUG_WARN("HEALTH", "OTA 前检查: WiFi 未连接");
|
||||
return HEALTH_MON_CRITICAL;
|
||||
}
|
||||
|
||||
int8_t last_rssi = -127;
|
||||
uint32_t age_ms = 0;
|
||||
if (health_get_last_wifi_rssi(&last_rssi, &age_ms)) {
|
||||
if (getLastWifiRssi(&last_rssi, &age_ms)) {
|
||||
if (age_ms <= OTA_WIFI_RSSI_SAMPLE_MAX_AGE_MS) {
|
||||
if (last_rssi < OTA_WIFI_RSSI_CRITICAL) {
|
||||
DEBUG_WARN("HEALTH", "OTA 前检查: 最近 RSSI %d < %d (样本年龄 %lu ms)",
|
||||
@@ -239,21 +207,21 @@ health_status_t health_check_before_ota(void)
|
||||
return status;
|
||||
}
|
||||
|
||||
health_status_t health_check_before_ota_relay(void)
|
||||
health_status_t HealthMonitor::checkBeforeOtaRelay()
|
||||
{
|
||||
health_status_t status = HEALTH_MON_OK;
|
||||
|
||||
if (g_health_state >= SYS_SAFE_SHUTDOWN) {
|
||||
if (healthState >= SYS_SAFE_SHUTDOWN) {
|
||||
DEBUG_WARN("HEALTH", "OTA 中继检查: SYS_SAFE_SHUTDOWN,禁止传输");
|
||||
return HEALTH_MON_SHUTDOWN;
|
||||
} else if (g_health_state >= SYS_CRITICAL) {
|
||||
} else if (healthState >= SYS_CRITICAL) {
|
||||
/* SYS_CRITICAL 可能是由 WiFi RSSI 过低导致的,
|
||||
* 但 SPI 中继阶段不依赖 WiFi,只检查温度/硬件等本地状态。
|
||||
* 温度达到 TEMP_CRITICAL(100°C) 时 g_health_state 会被设为
|
||||
* SYS_SAFE_SHUTDOWN,在上面的分支已经拦截。
|
||||
* 所以 SYS_CRITICAL 在中继阶段只可能是 WiFi 导致的,允许继续。 */
|
||||
DEBUG_WARN("HEALTH", "OTA 中继检查: SYS_CRITICAL (WiFi 相关),SPI 中继允许继续");
|
||||
} else if (g_health_state >= SYS_WARNING) {
|
||||
} else if (healthState >= SYS_WARNING) {
|
||||
status = HEALTH_MON_WARNING;
|
||||
DEBUG_WARN("HEALTH", "OTA 中继检查: SYS_WARNING,继续传输");
|
||||
}
|
||||
@@ -269,35 +237,30 @@ health_status_t health_check_before_ota_relay(void)
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据 WiFi RSSI 更新健康状态并返回检查结果。
|
||||
* @param rssi 当前 WiFi 信号强度(dBm)。
|
||||
* @return 健康检查结果。
|
||||
*/
|
||||
health_status_t health_update_from_wifi_rssi(int8_t rssi)
|
||||
// ============================================================
|
||||
// WiFi RSSI 更新
|
||||
// ============================================================
|
||||
health_status_t HealthMonitor::updateFromWifiRssi(int8_t rssi)
|
||||
{
|
||||
if (rssi < WIFI_RSSI_CRITICAL) {
|
||||
/** @brief 全局健康状态,受互斥锁保护。 */
|
||||
g_health_state = SYS_CRITICAL;
|
||||
healthState = SYS_CRITICAL;
|
||||
DEBUG_WARN("HEALTH", "WiFi RSSI 危险: %d dBm < %d dBm", rssi, WIFI_RSSI_CRITICAL);
|
||||
health_log_event("WIFI危险", rssi);
|
||||
logEvent("WIFI危险", rssi);
|
||||
return HEALTH_MON_CRITICAL;
|
||||
} else if (rssi < WIFI_RSSI_NORMAL) {
|
||||
if (g_health_state < SYS_WARNING) {
|
||||
/** @brief 全局健康状态,受互斥锁保护。 */
|
||||
g_health_state = SYS_WARNING;
|
||||
if (healthState < SYS_WARNING) {
|
||||
healthState = SYS_WARNING;
|
||||
DEBUG_WARN("HEALTH", "WiFi RSSI 警告: %d dBm < %d dBm", rssi, WIFI_RSSI_NORMAL);
|
||||
health_log_event("WIFI警告", rssi);
|
||||
logEvent("WIFI警告", rssi);
|
||||
}
|
||||
return HEALTH_MON_WARNING;
|
||||
}
|
||||
|
||||
if (g_health_state == SYS_WARNING && rssi >= WIFI_RSSI_NORMAL) {
|
||||
/** @brief 全局健康状态,受互斥锁保护。 */
|
||||
g_health_state = SYS_NORMAL;
|
||||
if (healthState == SYS_WARNING && rssi >= WIFI_RSSI_NORMAL) {
|
||||
healthState = SYS_NORMAL;
|
||||
DEBUG_INFO("HEALTH", "WiFi RSSI 恢复: %d dBm >= %d dBm", rssi, WIFI_RSSI_NORMAL);
|
||||
health_log_event("WIFI恢复", rssi);
|
||||
logEvent("WIFI恢复", rssi);
|
||||
}
|
||||
|
||||
return HEALTH_MON_OK;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user