feat(ota_relay): 实现WiFi/AP双模式和CANFD 3通道SPI协议

- 新增AP/STA双工作模式,通过app_config.h配置切换
- 实现CANFD 3通道SPI协议,支持主通信通道和备用通道
- 添加GD32命令ID定义和HTTP API接口
- 集成上位机WebUI,支持固件上传和CAN帧发送

refactor(debug_log): 支持UDP+UART双通道调试输出

- 新增UART0串口调试功能,TX=GPIO21, RX=GPIO20, 115200波特率
- 实现UDP socket延迟创建机制,避免网络初始化冲突
- 调试日志同时输出到UDP和UART双通道

docs(README): 更新项目文档和目录结构说明

- 更新硬件平台和模块功能描述
- 添加WiFi工作模式配置说明
- 补充CANFD协议和GD32命令定义
- 增加HTTP API和上位机WebUI使用指南

fix(health_monitor): 优化健康监控和系统状态报告

- 增强温度和电压监控的警告提示信息
- 添加WiFi RSSI监控和健康状态更新
- 修复安全关机触发条件和状态变更日志

style(main): 优化程序入口和任务创建流程

- 修复网络接口初始化顺序问题
- 添加任务创建结果检查和错误处理
- 增加系统启动信息和CPU频率显示
- 新增周期性状态监控任务,每10秒打印系统状态
This commit is contained in:
小龙虾
2026-04-28 01:06:17 +08:00
parent 47ffe1bd54
commit 064eb7e03f
11 changed files with 563 additions and 115 deletions
+46 -13
View File
@@ -36,7 +36,7 @@ static httpd_handle_t s_http_server = NULL;
// ----------------------------------------
static esp_err_t wifi_init_ap(void)
{
DEBUG_INFO("WIFI", "初始化 WiFi AP 模式...");
DEBUG_INFO("WIFI", "=== 初始化 WiFi AP 模式 ===");
s_wifi_mode = OTA_WIFI_MODE_AP;
@@ -48,12 +48,15 @@ static esp_err_t wifi_init_ap(void)
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
wifi_config.ap.channel = WIFI_AP_CHANNEL;
DEBUG_INFO("WIFI", "AP SSID: %s, Channel: %d", WIFI_AP_SSID, WIFI_AP_CHANNEL);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
DEBUG_INFO("WIFI", "WiFi AP 已启动: %s", WIFI_AP_SSID);
DEBUG_INFO("WIFI", "AP IP 地址: 192.168.4.1");
DEBUG_INFO("WIFI", "最大连接数: %d", WIFI_AP_MAX_CONNECT);
return ESP_OK;
}
@@ -63,7 +66,7 @@ static esp_err_t wifi_init_ap(void)
// ----------------------------------------
static esp_err_t wifi_init_sta(void)
{
DEBUG_INFO("WIFI", "初始化 WiFi STA 模式...");
DEBUG_INFO("WIFI", "=== 初始化 WiFi STA 模式 ===");
s_wifi_mode = OTA_WIFI_MODE_STA;
@@ -74,6 +77,8 @@ static esp_err_t wifi_init_sta(void)
memcpy(wifi_config.sta.ssid, WIFI_STA_SSID, strlen(WIFI_STA_SSID) + 1);
memcpy(wifi_config.sta.password, WIFI_STA_PASSWORD, strlen(WIFI_STA_PASSWORD) + 1);
DEBUG_INFO("WIFI", "STA SSID: %s", WIFI_STA_SSID);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
@@ -133,10 +138,11 @@ static void wifi_set_static_ip(void)
// ----------------------------------------
static esp_err_t ota_upload_handler(httpd_req_t *req)
{
DEBUG_INFO("WIFI", "收到固件上传请求, 内容长度: %d", req->content_len);
DEBUG_INFO("WIFI", "=== HTTP: POST /ota/upload ===");
DEBUG_INFO("WIFI", "收到固件上传请求, 内容长度: %d 字节", req->content_len);
if (req->content_len > OTA_MAX_FIRMWARE_SIZE) {
DEBUG_ERR("WIFI", "固件太大: %d 字节", req->content_len);
DEBUG_ERR("WIFI", "固件太大: %d 字节 (最大 %d)", req->content_len, OTA_MAX_FIRMWARE_SIZE);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "固件太大");
return ESP_FAIL;
}
@@ -151,7 +157,7 @@ static esp_err_t ota_upload_handler(httpd_req_t *req)
int ret = httpd_req_recv(req, (char *)buf, to_read);
if (ret <= 0) {
DEBUG_ERR("WIFI", "请求接收失败");
DEBUG_ERR("WIFI", "HTTP 请求接收失败");
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "接收失败");
return ESP_FAIL;
}
@@ -169,7 +175,8 @@ static esp_err_t ota_upload_handler(httpd_req_t *req)
.checksum = {0}
};
meta_save(&meta);
DEBUG_INFO("WIFI", "开始固件存储: %u 字节", total_size);
DEBUG_INFO("WIFI", "开始固件存储: %u 字节, %u 块",
total_size, meta.chunk_count);
}
first_chunk = 0;
}
@@ -177,13 +184,18 @@ static esp_err_t ota_upload_handler(httpd_req_t *req)
uint32_t flash_offset = (received / OTA_BLOCK_SIZE) * OTA_BLOCK_SIZE;
esp_err_t err = flash_write_chunk(flash_offset, buf, ret);
if (err != ESP_OK) {
DEBUG_ERR("WIFI", "Flash 写入失败 at offset %u", flash_offset);
DEBUG_ERR("WIFI", "Flash 写入失败, offset=%u, err=%d", flash_offset, err);
}
meta_update(flash_offset + ret, received / OTA_BLOCK_SIZE);
received += ret;
DEBUG_DBG("WIFI", "已接收: %d / %d 字节", received, req->content_len);
// 每 10% 打印进度
if (received % (req->content_len / 10 + 1) < OTA_BLOCK_SIZE) {
uint32_t progress = (received * 100) / req->content_len;
DEBUG_INFO("WIFI", "上传进度: %d / %d 字节 (%u%%)", received, req->content_len, progress);
}
}
DEBUG_INFO("WIFI", "固件存储完成: %d 字节", received);
@@ -207,6 +219,7 @@ static esp_err_t ota_upload_handler(httpd_req_t *req)
static esp_err_t ota_relay_trigger_handler(httpd_req_t *req)
{
(void)req;
DEBUG_INFO("WIFI", "=== HTTP: POST /ota/relay ===");
DEBUG_INFO("WIFI", "收到触发 OTA 中继请求");
wifi_ota_signal_relay();
@@ -220,6 +233,8 @@ static esp_err_t ota_relay_trigger_handler(httpd_req_t *req)
// HTTP GET /ota/status 处理器
static esp_err_t ota_status_handler(httpd_req_t *req)
{
DEBUG_INFO("WIFI", "=== HTTP: GET /ota/status ===");
ota_meta_t meta;
meta_load(&meta);
@@ -232,6 +247,10 @@ static esp_err_t ota_status_handler(httpd_req_t *req)
s_ota_storage_done ? "true" : "false",
g_relay_state);
DEBUG_INFO("WIFI", "OTA 状态: total=%lu, stored=%lu, done=%s",
(unsigned long)meta.total_size, (unsigned long)meta.stored_size,
s_ota_storage_done ? "true" : "false");
httpd_resp_set_type(req, "application/json");
httpd_resp_send(req, resp, len);
@@ -241,12 +260,17 @@ static esp_err_t ota_status_handler(httpd_req_t *req)
// HTTP GET /health 处理器
static esp_err_t health_handler(httpd_req_t *req)
{
DEBUG_INFO("WIFI", "=== HTTP: GET /health ===");
health_state_t state = health_get_current();
uint32_t free_heap = esp_get_free_heap_size();
char resp[128];
int len = snprintf(resp, sizeof(resp),
"{\"health\": %d, \"free_heap\": %lu}",
state, (unsigned long)esp_get_free_heap_size());
state, (unsigned long)free_heap);
DEBUG_INFO("WIFI", "健康状态: %d, 空闲堆: %lu", state, (unsigned long)free_heap);
httpd_resp_set_type(req, "application/json");
httpd_resp_send(req, resp, len);
@@ -386,7 +410,8 @@ static esp_err_t http_ota_server_start(void)
config.server_port = HTTP_SERVER_PORT;
config.stack_size = HTTP_SERVER_STACK_SIZE;
DEBUG_INFO("WIFI", "启动 HTTP 服务器,端口 %d...", config.server_port);
DEBUG_INFO("WIFI", "=== 启动 HTTP OTA 服务器 ===");
DEBUG_INFO("WIFI", "HTTP 服务器端口: %d", config.server_port);
esp_err_t err = httpd_start(&s_http_server, &config);
if (err != ESP_OK) {
@@ -452,6 +477,7 @@ static esp_err_t http_ota_server_start(void)
httpd_register_uri_handler(s_http_server, &can_status_uri);
DEBUG_INFO("WIFI", "HTTP 服务器已启动");
DEBUG_INFO("WIFI", "注册端点: /ota/upload, /ota/relay, /ota/status, /health, /wifi/status, /can/send, /can/status");
return ESP_OK;
}
@@ -504,19 +530,23 @@ void wifi_ota_task(void *pvParameters)
{
(void)pvParameters;
DEBUG_INFO("WIFI", "WiFi OTA 任务启动");
DEBUG_INFO("WIFI", "=== WiFi OTA 任务启动 ===");
// 初始化 NVS
esp_err_t err = nvs_flash_init();
if (err != ESP_OK) {
DEBUG_ERR("WIFI", "NVS 初始化失败: %s", esp_err_to_name(err));
} else {
DEBUG_INFO("WIFI", "NVS 初始化成功");
}
// 初始化网络接口
ESP_ERROR_CHECK(esp_netif_init());
DEBUG_INFO("WIFI", "网络接口初始化成功");
// STA 优先,失败自动切 AP
#if CONFIG_WIFI_MODE_IS_STA
DEBUG_INFO("WIFI", "工作模式: STA (优先)");
err = wifi_init_sta();
if (err == ESP_OK) {
char ip_str[16] = {0};
@@ -536,6 +566,7 @@ void wifi_ota_task(void *pvParameters)
}
}
#else
DEBUG_INFO("WIFI", "工作模式: AP");
wifi_init_ap();
#endif
@@ -545,7 +576,7 @@ void wifi_ota_task(void *pvParameters)
DEBUG_ERR("WIFI", "HTTP 服务器启动失败");
}
DEBUG_INFO("WIFI", "WiFi OTA 服务器就绪");
DEBUG_INFO("WIFI", "=== WiFi OTA 服务器就绪 ===");
// 定期检查 WiFi 状态
while (1) {
@@ -554,7 +585,9 @@ void wifi_ota_task(void *pvParameters)
health_update_from_wifi_rssi(rssi);
if (rssi < WIFI_RSSI_CRITICAL) {
DEBUG_WARN("WIFI", "WiFi RSSI 危险: %d dBm", rssi);
DEBUG_WARN("WIFI", "WiFi RSSI 危险: %d dBm (阈值: %d)", rssi, WIFI_RSSI_CRITICAL);
} else if (rssi < WIFI_RSSI_WARNING) {
DEBUG_WARN("WIFI", "WiFi RSSI 较弱: %d dBm", rssi);
}
}