diff --git a/.vscode/settings.json b/.vscode/settings.json index f54e4d2..8621c2d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,7 @@ "idf.openOcdConfigs": [ "board/esp32c3-bridge.cfg" ], - "idf.portWin": "COM11", + "idf.portWin": "COM13", "idf.currentSetup": "F:\\software\\.espressif\\v6.0\\esp-idf", "idf.customExtraVars": { "IDF_TARGET": "esp32c3" diff --git a/README.md b/README.md index 2a69189..85de683 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ ESP32_COMM/ CONFIG_WIFI_MODE_IS_STA = 0 WIFI_AP_SSID = "ESP32_OTA_RELAY" // 默认热点名称 WIFI_AP_PASSWORD = "12345678" // 默认密码 -// 上位机连接热点后访问: http://192.168.4.1 +// 上位机连接热点后访问: http://192.168.31.1 // STA 模式(连接路由器) CONFIG_WIFI_MODE_IS_STA = 1 @@ -98,7 +98,7 @@ GD32 通信帧格式:`[通道编号: 1B] [扩展帧ID: 4B BE] [数据: 1~64B]` ### CAN 帧发送示例 ```bash -curl -X POST http://192.168.4.1/can/send \ +curl -X POST http://192.168.31.1/can/send \ -H "Content-Type: application/json" \ -d '{"ch": 0, "id": 12345678, "dlc": 8, "data": "0102030405060708"}' ``` diff --git a/_assistant_backups/2026-05-04/health_monitor.cpp.bak_2026-05-04_2233 b/_assistant_backups/2026-05-04/health_monitor.cpp.bak_2026-05-04_2233 new file mode 100644 index 0000000..ee9b967 --- /dev/null +++ b/_assistant_backups/2026-05-04/health_monitor.cpp.bak_2026-05-04_2233 @@ -0,0 +1,233 @@ +/* + * health_monitor.cpp - 系统健康监控 + * 包含:健康状态管理 + WiFi RSSI 监控 + 温度监控 + 电压监控 + */ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_wifi.h" +#include "esp_timer.h" +#include "esp_err.h" +#include "driver/temperature_sensor.h" + +#include "health_monitor.h" +#include "debug_log.h" + +health_state_t g_health_state = SYS_NORMAL; + +static SemaphoreHandle_t g_health_mutex = NULL; +static temperature_sensor_handle_t s_temp_handle = NULL; + +// ---------------------------------------- +// 健康状态管理 +// ---------------------------------------- +void health_monitor_init(void) +{ + g_health_mutex = xSemaphoreCreateMutex(); + if (g_health_mutex == NULL) { + DEBUG_ERR("HEALTH", "创建健康状态互斥锁失败"); + } +} + +health_state_t health_get_current(void) +{ + health_state_t state; + if (g_health_mutex) { + xSemaphoreTake(g_health_mutex, portMAX_DELAY); + } + state = g_health_state; + if (g_health_mutex) { + xSemaphoreGive(g_health_mutex); + } + return state; +} + +// ---------------------------------------- +// 温度监控(定时器回调) +// ---------------------------------------- +static void temp_monitor_callback(void *arg) +{ + float temp = 0.0f; + esp_err_t err = temperature_sensor_get_celsius(s_temp_handle, &temp); + if (err != ESP_OK) { + DEBUG_WARN("TEMP", "读取温度失败: %s", esp_err_to_name(err)); + return; + } + + DEBUG_DBG("TEMP", "芯片温度: %.1f°C", temp); + + if (temp >= TEMP_CRITICAL) { + g_health_state = 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) { + g_health_state = SYS_WARNING; + DEBUG_WARN("TEMP", "警告: 温度 %.1f°C >= %d°C", temp, TEMP_WARNING); + DEBUG_WARN("TEMP", "健康状态变更为: SYS_WARNING"); + } + } +} + +// ---------------------------------------- +// 电压监控(启动时调用一次) +// ---------------------------------------- +static void voltage_monitor_callback(void *arg) +{ + float voltage = 3.30f; // ESP32-C3 无内置电压传感器,使用估算 + DEBUG_DBG("VOLT", "VDD 电压: %.2fV (估算)", voltage); + + if (voltage < 2.3f) { + g_health_state = SYS_SAFE_SHUTDOWN; + DEBUG_ERR("VOLT", "!!! 危险 !!! 电压 %.2fV < 2.3V,触发安全关机", voltage); + DEBUG_ERR("VOLT", "健康状态变更为: SYS_SAFE_SHUTDOWN"); + } else if (voltage < 2.5f) { + if (g_health_state < SYS_WARNING) { + g_health_state = SYS_WARNING; + DEBUG_WARN("VOLT", "警告: 电压 %.2fV < 2.5V", voltage); + DEBUG_WARN("VOLT", "健康状态变更为: SYS_WARNING"); + } + } else { + DEBUG_INFO("VOLT", "电压正常: %.2fV", voltage); + } +} + +// ---------------------------------------- +// 温度电压监控任务入口 +// ---------------------------------------- +void health_monitor_task(void *pvParameters) +{ + DEBUG_INFO("MON", "=== 健康监控任务启动 ==="); + + // 初始化内置温度传感器(测量范围 20°C ~ 80°C) + temperature_sensor_config_t temp_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(20, 80); + esp_err_t err = temperature_sensor_install(&temp_config, &s_temp_handle); + if (err != ESP_OK) { + DEBUG_ERR("MON", "温度传感器初始化失败: %s", esp_err_to_name(err)); + } else { + ESP_ERROR_CHECK(temperature_sensor_enable(s_temp_handle)); + DEBUG_INFO("MON", "温度传感器已启用 (范围 20°C ~ 80°C)"); + } + + // 定时器,每5秒读取一次温度 + esp_timer_handle_t temp_timer; + esp_timer_create_args_t timer_args = {}; + timer_args.callback = &temp_monitor_callback; + 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, 5 * 1000000); // 5秒 + + DEBUG_INFO("MON", "温度监控定时器已启动 (间隔 5 秒)"); + + // 启动时检查一次电压 + voltage_monitor_callback(NULL); + + // 每5秒打印一次健康状态 + uint32_t loop_count = 0; + while (1) { + loop_count++; + + uint32_t free_heap = esp_get_free_heap_size(); + + const char *state_str; + switch (g_health_state) { + case SYS_NORMAL: state_str = "正常"; break; + case SYS_WARNING: state_str = "警告"; break; + case SYS_CRITICAL: state_str = "危险"; break; + case SYS_SAFE_SHUTDOWN: state_str = "安全关机"; break; + default: state_str = "未知"; break; + } + + DEBUG_INFO("MON", "--- 健康状态 #%lu ---", (unsigned long)loop_count); + DEBUG_INFO("MON", "健康状态: %s (%d)", state_str, g_health_state); + DEBUG_INFO("MON", "空闲堆: %lu 字节", (unsigned long)free_heap); + + // 堆内存警告 + if (free_heap < HEAP_WARNING_MIN) { + DEBUG_WARN("MON", "空闲堆内存不足: %lu < %d", (unsigned long)free_heap, HEAP_WARNING_MIN); + } + + DEBUG_INFO("MON", "==================="); + + vTaskDelay(pdMS_TO_TICKS(5000)); + } +} + +// ---------------------------------------- +// 健康事件日志 +// ---------------------------------------- +void health_log_event(const char *event, int value) +{ + DEBUG_INFO("HEALTH", "[健康事件] %s: %d", event, value); +} + +// ---------------------------------------- +// OTA 传输前的健康检查 +// ---------------------------------------- +health_status_t health_check_before_ota(void) +{ + health_status_t status = HEALTH_MON_OK; + + if (g_health_state >= SYS_SAFE_SHUTDOWN) { + DEBUG_WARN("HEALTH", "OTA 前检查: SYS_SAFE_SHUTDOWN,禁止传输"); + return HEALTH_MON_SHUTDOWN; + } else if (g_health_state >= SYS_CRITICAL) { + DEBUG_WARN("HEALTH", "OTA 前检查: SYS_CRITICAL,禁止传输"); + return HEALTH_MON_CRITICAL; + } else if (g_health_state >= SYS_WARNING) { + status = HEALTH_MON_WARNING; + DEBUG_WARN("HEALTH", "OTA 前检查: SYS_WARNING,继续传输但需注意"); + } + + wifi_ap_record_t ap_info; + if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) { + if (ap_info.rssi < WIFI_RSSI_CRITICAL) { + g_health_state = SYS_CRITICAL; + DEBUG_WARN("HEALTH", "OTA 前检查: WiFi RSSI %d < %d (危险阈值)", + ap_info.rssi, WIFI_RSSI_CRITICAL); + return HEALTH_MON_CRITICAL; + } else if (ap_info.rssi < WIFI_RSSI_NORMAL) { + if (status < HEALTH_MON_WARNING) { + status = HEALTH_MON_WARNING; + } + DEBUG_WARN("HEALTH", "OTA 前检查: WiFi RSSI %d < %d (警告阈值)", + ap_info.rssi, WIFI_RSSI_NORMAL); + } + } + + if (status == HEALTH_MON_OK) { + DEBUG_DBG("HEALTH", "OTA 前检查: 正常"); + } + + return status; +} + +health_status_t health_update_from_wifi_rssi(int8_t rssi) +{ + if (rssi < WIFI_RSSI_CRITICAL) { + g_health_state = SYS_CRITICAL; + DEBUG_WARN("HEALTH", "WiFi RSSI 危险: %d dBm < %d dBm", rssi, WIFI_RSSI_CRITICAL); + health_log_event("WIFI危险", rssi); + return HEALTH_MON_CRITICAL; + } else if (rssi < WIFI_RSSI_NORMAL) { + if (g_health_state < SYS_WARNING) { + g_health_state = SYS_WARNING; + DEBUG_WARN("HEALTH", "WiFi RSSI 警告: %d dBm < %d dBm", rssi, WIFI_RSSI_NORMAL); + health_log_event("WIFI警告", rssi); + } + return HEALTH_MON_WARNING; + } + + if (g_health_state == SYS_WARNING && rssi >= WIFI_RSSI_NORMAL) { + g_health_state = SYS_NORMAL; + DEBUG_INFO("HEALTH", "WiFi RSSI 恢复: %d dBm >= %d dBm", rssi, WIFI_RSSI_NORMAL); + health_log_event("WIFI恢复", rssi); + } + + return HEALTH_MON_OK; +} diff --git a/_assistant_backups/2026-05-04/health_monitor.h.bak_2026-05-04_2233 b/_assistant_backups/2026-05-04/health_monitor.h.bak_2026-05-04_2233 new file mode 100644 index 0000000..34574c5 --- /dev/null +++ b/_assistant_backups/2026-05-04/health_monitor.h.bak_2026-05-04_2233 @@ -0,0 +1,37 @@ +/* + * health_monitor.h - 系统健康监控头文件 + */ +#pragma once + +#include +#include "app_config.h" + +// T9.3: 健康状态等级 +typedef enum { + SYS_NORMAL = 0, // 正常 + SYS_WARNING = 1, // 警告 + SYS_CRITICAL = 2, // 危险 + SYS_SAFE_SHUTDOWN = 3 // 安全关机 +} health_state_t; + +typedef enum { + HEALTH_MON_OK = 0, + HEALTH_MON_WARNING = 1, + HEALTH_MON_CRITICAL = 2, + HEALTH_MON_SHUTDOWN = 3 +} health_status_t; + +// 外部共享状态(互斥锁保护) +extern health_state_t g_health_state; + +// WiFi RSSI 阈值(来自 app_config.h) +#define WIFI_RSSI_NORMAL WIFI_RSSI_WARNING +#define WIFI_RSSI_WEAK WIFI_RSSI_CRITICAL + +// 函数声明 +void health_monitor_init(void); +void health_monitor_task(void *pvParameters); +health_status_t health_check_before_ota(void); +void health_log_event(const char *event, int value); +health_state_t health_get_current(void); +health_status_t health_update_from_wifi_rssi(int8_t rssi); diff --git a/_assistant_backups/2026-05-04/wifi_ota.cpp.bak_2026-05-04_2132 b/_assistant_backups/2026-05-04/wifi_ota.cpp.bak_2026-05-04_2132 new file mode 100644 index 0000000..1581306 --- /dev/null +++ b/_assistant_backups/2026-05-04/wifi_ota.cpp.bak_2026-05-04_2132 @@ -0,0 +1,972 @@ +/* + * wifi_ota.c - WiFi OTA 服务器实现 + * T4.1 - T4.5 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_wifi.h" +#include "esp_netif.h" +#include "esp_http_server.h" +#include "esp_system.h" +#include "esp_timer.h" +#include "esp_ota_ops.h" +#include "nvs_flash.h" +#include "lwip/netdb.h" +#include "esp_netif.h" +#include "esp_netif_types.h" +#include "esp_event.h" +#include "esp_mac.h" + +#include "app_config.h" +#include "wifi_ota.h" +#include "ota_relay.h" +#include "health_monitor.h" +#include "monitor/debug_log.h" +#include "spi_master.h" +#include "cJSON.h" + +static ota_wifi_mode_t s_wifi_mode = OTA_WIFI_MODE_AP; +static bool s_relay_triggered = false; +static bool s_sta_connected = false; +static int s_sta_retry_count = 0; +static SemaphoreHandle_t s_sta_connected_sem = NULL; +static SemaphoreHandle_t s_sta_got_ip_sem = NULL; + +// ESP32 OTA 状态 +static bool s_esp32_ota_active = false; +static esp_ota_handle_t s_esp32_ota_handle = 0; +static const esp_partition_t *s_esp32_update_partition = NULL; +static size_t s_esp32_received = 0; + +// GD32 OTA 存储状态 +static bool s_gd32_storage_done = false; + +static httpd_handle_t s_http_server = NULL; + +static void wifi_set_static_ip(void); + +// ---------------------------------------- +// WiFi/IP 事件回调(事件驱动连接) +// ---------------------------------------- +static void wifi_event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT) { + switch (event_id) { + case WIFI_EVENT_STA_START: + DEBUG_INFO("WIFI", "STA 已启动,开始连接..."); + esp_wifi_connect(); + break; + + case WIFI_EVENT_STA_CONNECTED: + DEBUG_INFO("WIFI", "STA 已关联到 AP"); + s_sta_connected = true; + s_sta_retry_count = 0; + if (s_sta_connected_sem) { + xSemaphoreGive(s_sta_connected_sem); + } + break; + + case WIFI_EVENT_STA_DISCONNECTED: { + wifi_event_sta_disconnected_t* disconn = (wifi_event_sta_disconnected_t*)event_data; + DEBUG_WARN("WIFI", "STA 断开, reason=%d, retry=%d", disconn->reason, s_sta_retry_count); + s_sta_connected = false; + + if (s_sta_retry_count < WIFI_STA_MAX_RETRY) { + s_sta_retry_count++; + DEBUG_INFO("WIFI", "重连第 %d 次...", s_sta_retry_count); + esp_wifi_connect(); + } else { + DEBUG_ERR("WIFI", "STA 重连失败 %d 次,放弃", s_sta_retry_count); + } + break; + } + + case WIFI_EVENT_AP_STACONNECTED: { + wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*)event_data; + DEBUG_INFO("WIFI", "AP: 客户端 " MACSTR " 连入, AID=%d", MAC2STR(event->mac), event->aid); + break; + } + + case WIFI_EVENT_AP_STADISCONNECTED: { + wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*)event_data; + DEBUG_INFO("WIFI", "AP: 客户端 " MACSTR " 离开, AID=%d, reason=%d", + MAC2STR(event->mac), event->aid, event->reason); + break; + } + + default: + break; + } + } else if (event_base == IP_EVENT) { + switch (event_id) { + case IP_EVENT_STA_GOT_IP: { + ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data; + DEBUG_INFO("WIFI", "STA 获取 IP: " IPSTR, IP2STR(&event->ip_info.ip)); + if (s_sta_got_ip_sem) { + xSemaphoreGive(s_sta_got_ip_sem); + } + break; + } + + default: + break; + } + } +} + +// ---------------------------------------- +// WiFi AP 模式初始化 +// ---------------------------------------- +static esp_err_t wifi_init_ap(void) +{ + DEBUG_INFO("WIFI", "=== 初始化 WiFi AP 模式 ==="); + + s_wifi_mode = OTA_WIFI_MODE_AP; + + // 创建 AP netif 并设置自定义 IP + esp_netif_t *ap_netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"); + if (ap_netif == NULL) { + ap_netif = esp_netif_create_default_wifi_ap(); + } + if (ap_netif != NULL) { + // 停止 DHCP 服务器(必须先停才能改 IP) + esp_netif_dhcps_stop(ap_netif); + + esp_netif_ip_info_t ip_info; + memset(&ip_info, 0, sizeof(ip_info)); + // 方案 A:SoftAP 使用 192.168.31.0/24 网段 + // ESP32 自己作为 AP 网关,电脑连入后拿到 192.168.31.x + inet_pton(AF_INET, "192.168.31.1", &ip_info.ip); + inet_pton(AF_INET, "192.168.31.1", &ip_info.gw); + inet_pton(AF_INET, "255.255.255.0", &ip_info.netmask); + ESP_ERROR_CHECK(esp_netif_set_ip_info(ap_netif, &ip_info)); + + // 重新启动 DHCP 服务器,给连接的客户端分配 IP + esp_netif_dhcps_start(ap_netif); + DEBUG_INFO("WIFI", "AP IP 已设置: 192.168.31.1"); + } + + wifi_config_t wifi_config = {}; + memcpy(wifi_config.ap.ssid, WIFI_AP_SSID, strlen(WIFI_AP_SSID) + 1); + wifi_config.ap.ssid_len = strlen(WIFI_AP_SSID); + memcpy(wifi_config.ap.password, WIFI_AP_PASSWORD, strlen(WIFI_AP_PASSWORD) + 1); + wifi_config.ap.max_connection = WIFI_AP_MAX_CONNECT; + 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.31.1"); + DEBUG_INFO("WIFI", "AP 网关地址: 192.168.31.1"); + DEBUG_INFO("WIFI", "最大连接数: %d", WIFI_AP_MAX_CONNECT); + + return ESP_OK; +} + +// ---------------------------------------- +// WiFi STA 模式初始化 +// ---------------------------------------- +static esp_err_t wifi_init_sta(void) +{ + DEBUG_INFO("WIFI", "=== 初始化 WiFi STA 模式 ==="); + + s_wifi_mode = OTA_WIFI_MODE_STA; + s_sta_retry_count = 0; + + // ★ 设置国家代码:中国,允许信道 1-13 + // ESP32 默认国家是 US(只允许 1-11),中国路由可能用 12/13 + wifi_country_t country = {}; + memcpy(country.cc, "CN", 3); + country.schan = 1; + country.nchan = 13; + country.policy = WIFI_COUNTRY_POLICY_MANUAL; + + wifi_config_t wifi_config = {}; + wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; + wifi_config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL; + wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; + wifi_config.sta.pmf_cfg.capable = true; + wifi_config.sta.pmf_cfg.required = false; + wifi_config.sta.listen_interval = 3; + 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 (全信道扫描, CN 国家代码)", WIFI_STA_SSID); + + ESP_ERROR_CHECK(esp_wifi_set_country(&country)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + + // 静态 IP 必须在 start/connect 之前配置,避免与 STA_START 自动连接发生竞态 + wifi_set_static_ip(); + + ESP_ERROR_CHECK(esp_wifi_start()); + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); + + DEBUG_INFO("WIFI", "WiFi STA 启动, SSID: %s, 事件驱动连接...", WIFI_STA_SSID); + + return ESP_OK; +} + +// 等待 STA 连接成功并获取 IP(静态 IP 等 CONNECTED,DHCP 等 GOT_IP) +static esp_err_t wifi_wait_sta_connected(char *ip_str, size_t len) +{ + SemaphoreHandle_t wait_sem = WIFI_STA_USE_STATIC_IP ? s_sta_connected_sem : s_sta_got_ip_sem; + const char *wait_name = WIFI_STA_USE_STATIC_IP ? "STA_CONNECTED" : "STA_GOT_IP"; + + if (wait_sem == NULL) { + DEBUG_ERR("WIFI", "%s 信号量未创建", wait_name); + return ESP_ERR_INVALID_STATE; + } + + TickType_t timeout_ticks = pdMS_TO_TICKS(WIFI_STA_CONNECT_TIMEOUT_MS); + if (xSemaphoreTake(wait_sem, timeout_ticks) == pdTRUE) { + esp_netif_ip_info_t ip_info; + esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (netif != NULL && esp_netif_get_ip_info(netif, &ip_info) == ESP_OK) { + if (ip_str) { + snprintf(ip_str, len, IPSTR, IP2STR(&ip_info.ip)); + } + DEBUG_INFO("WIFI", "%s 等待成功, 当前 IP: " IPSTR, wait_name, IP2STR(&ip_info.ip)); + } + s_sta_connected = true; + return ESP_OK; + } + + DEBUG_ERR("WIFI", "等待 %s 超时 (%d ms), 重连次数: %d", wait_name, WIFI_STA_CONNECT_TIMEOUT_MS, s_sta_retry_count); + return ESP_ERR_TIMEOUT; +} + +// 设置 STA 静态 IP +static void wifi_set_static_ip(void) +{ + if (WIFI_STA_USE_STATIC_IP) { + esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (sta_netif) { + DEBUG_INFO("WIFI", "STA 使用静态 IP 模式,停止 DHCP Client"); + ESP_ERROR_CHECK(esp_netif_dhcpc_stop(sta_netif)); + + esp_netif_ip_info_t info; + memset(&info, 0, sizeof(info)); + inet_pton(AF_INET, WIFI_STA_STATIC_IP, &info.ip); + inet_pton(AF_INET, WIFI_STA_STATIC_GW, &info.gw); + inet_pton(AF_INET, WIFI_STA_STATIC_NETMASK, &info.netmask); + ESP_ERROR_CHECK(esp_netif_set_ip_info(sta_netif, &info)); + DEBUG_INFO("WIFI", "静态 IP 已设置: %s", WIFI_STA_STATIC_IP); + + // 设置 DNS + esp_netif_dns_info_t dns_info; + memset(&dns_info, 0, sizeof(dns_info)); + inet_pton(AF_INET, WIFI_STA_STATIC_DNS, &dns_info.ip.u_addr.ip4.addr); + ESP_ERROR_CHECK(esp_netif_set_dns_info(sta_netif, ESP_NETIF_DNS_MAIN, &dns_info)); + DEBUG_INFO("WIFI", "DNS 已设置: %s", WIFI_STA_STATIC_DNS); + } + } else { + DEBUG_INFO("WIFI", "使用 DHCP 获取 IP"); + } +} + +// ---------------------------------------- +// ESP32 OTA 内部函数 +// ---------------------------------------- +static esp_err_t esp32_ota_begin(size_t total_size) +{ + const esp_partition_t *boot_partition = esp_ota_get_running_partition(); + DEBUG_INFO("OTA", "当前启动分区: %s, size=%u, address=0x%lx", + boot_partition->label, boot_partition->size, boot_partition->address); + + s_esp32_update_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL); + if (s_esp32_update_partition == NULL || + s_esp32_update_partition->address == boot_partition->address) { + s_esp32_update_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL); + } + + if (s_esp32_update_partition == NULL) { + DEBUG_ERR("OTA", "找不到可用的 OTA 分区"); + return ESP_FAIL; + } + + DEBUG_INFO("OTA", "OTA 目标分区: %s, size=%u, address=0x%lx", + s_esp32_update_partition->label, + s_esp32_update_partition->size, + s_esp32_update_partition->address); + + if (total_size > s_esp32_update_partition->size) { + DEBUG_ERR("OTA", "固件太大: %u > 分区大小: %u", + total_size, s_esp32_update_partition->size); + return ESP_FAIL; + } + + esp_err_t err = esp_ota_begin(s_esp32_update_partition, total_size, &s_esp32_ota_handle); + if (err != ESP_OK) { + DEBUG_ERR("OTA", "esp_ota_begin 失败: %s", esp_err_to_name(err)); + s_esp32_update_partition = NULL; + return err; + } + + s_esp32_received = 0; + s_esp32_ota_active = true; + DEBUG_INFO("OTA", "ESP32 OTA 开始,目标分区: %s", s_esp32_update_partition->label); + return ESP_OK; +} + +static esp_err_t esp32_ota_write(const uint8_t *data, size_t len) +{ + if (!s_esp32_ota_active || s_esp32_update_partition == NULL) { + return ESP_ERR_INVALID_STATE; + } + esp_err_t err = esp_ota_write(s_esp32_ota_handle, data, len); + if (err == ESP_OK) { + s_esp32_received += len; + } + return err; +} + +// HTTP POST /ota/update - 完成 ESP32 OTA 并重启 +static esp_err_t esp32_ota_update_handler(httpd_req_t *req) +{ + (void)req; + if (!s_esp32_ota_active) { + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "OTA not started"); + return ESP_FAIL; + } + + DEBUG_INFO("OTA", "ESP32 OTA 完成, 共 %u 字节, 设置启动分区...", s_esp32_received); + + esp_err_t err = esp_ota_end(s_esp32_ota_handle); + if (err != ESP_OK) { + DEBUG_ERR("OTA", "esp_ota_end 失败: %s", esp_err_to_name(err)); + s_esp32_ota_active = false; + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, esp_err_to_name(err)); + return ESP_FAIL; + } + + err = esp_ota_set_boot_partition(s_esp32_update_partition); + if (err != ESP_OK) { + DEBUG_ERR("OTA", "esp_ota_set_boot_partition 失败: %s", esp_err_to_name(err)); + s_esp32_ota_active = false; + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, esp_err_to_name(err)); + return ESP_FAIL; + } + + s_esp32_ota_active = false; + DEBUG_INFO("OTA", "ESP32 OTA 完成,重启中..."); + + const char resp[] = "{\"status\": \"ok\", \"message\": \"OTA finished, rebooting\"}"; + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + + vTaskDelay(pdMS_TO_TICKS(500)); + esp_restart(); + return ESP_OK; +} + +// HTTP GET /ota/update - 查询 ESP32 OTA 状态 +static esp_err_t esp32_ota_status_handler(httpd_req_t *req) +{ + char resp[128]; + if (s_esp32_ota_active) { + snprintf(resp, sizeof(resp), + "{\"active\": true, \"received\": %u, \"partition\": \"%s\"}", + (unsigned int)s_esp32_received, + s_esp32_update_partition ? s_esp32_update_partition->label : "null"); + } else { + snprintf(resp, sizeof(resp), "{\"active\": false}"); + } + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + return ESP_OK; +} + +// ---------------------------------------- +// 统一 /ota/upload 处理器(自动识别目标) +// ---------------------------------------- +static esp_err_t ota_upload_handler(httpd_req_t *req) +{ + DEBUG_INFO("WIFI", "=== HTTP: POST /ota/upload ==="); + DEBUG_INFO("WIFI", "收到固件上传请求, 内容长度: %d 字节", req->content_len); + + // 先读取一小段判断是 JSON 还是 binary + char header[256]; + int header_read = httpd_req_recv(req, header, sizeof(header) - 1); + if (header_read <= 0) { + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "接收失败"); + return ESP_FAIL; + } + header[header_read] = '\0'; + + bool is_esp32_ota = false; + uint32_t total_size = 0; + + // 尝试解析 JSON + if (header_read > 0 && header[0] == '{') { + cJSON *root = cJSON_Parse(header); + if (root) { + cJSON *type_item = cJSON_GetObjectItem(root, "type"); + if (type_item && cJSON_IsString(type_item) && + strcmp(cJSON_GetStringValue(type_item), "esp32") == 0) { + is_esp32_ota = true; + DEBUG_INFO("WIFI", "检测到 ESP32 OTA"); + } + cJSON *size_item = cJSON_GetObjectItem(root, "total_size"); + if (size_item) { + total_size = (uint32_t)cJSON_GetNumberValue(size_item); + } + cJSON_Delete(root); + } + } + + if (is_esp32_ota) { + // --- ESP32 OTA --- + if (total_size == 0) { + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "missing total_size"); + return ESP_FAIL; + } + + esp_err_t err = esp32_ota_begin(total_size); + if (err != ESP_OK) { + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "OTA begin failed"); + return ESP_FAIL; + } + + // 先处理已读的 header + err = esp32_ota_write((const uint8_t *)header, header_read); + if (err != ESP_OK) { + DEBUG_ERR("WIFI", "OTA write 失败"); + return ESP_FAIL; + } + + // 继续读剩余数据 + size_t total_received = header_read; + while (total_received < req->content_len) { + size_t to_read = req->content_len - total_received; + if (to_read > 4096) to_read = 4096; + + int ret = httpd_req_recv(req, header, to_read); + if (ret <= 0) break; + + esp_err_t err = esp32_ota_write((const uint8_t *)header, ret); + if (err != ESP_OK) break; + total_received += ret; + + if (total_size > 0 && s_esp32_received % (total_size / 10 + 1) == 0) { + DEBUG_INFO("WIFI", "ESP32 OTA 进度: %u / %u (%u%%)", + (unsigned int)s_esp32_received, total_size, + (unsigned int)((s_esp32_received * 100) / total_size)); + } + } + + DEBUG_INFO("WIFI", "ESP32 OTA 存储完成: %u 字节", (unsigned int)s_esp32_received); + const char resp[] = "{\"status\": \"ok\", \"message\": \"stored, call POST /ota/update to finish\", \"target\": \"esp32\"}"; + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + return ESP_OK; + } + + // --- GD32 OTA(原逻辑)--- + if (req->content_len > OTA_MAX_FIRMWARE_SIZE) { + 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; + } + + uint8_t *buf = (uint8_t *)malloc(OTA_BLOCK_SIZE); + int received = 0; + + // 先处理已读的 header + if (header_read >= 6) { + uint16_t seq = header[0] | (header[1] << 8); + uint32_t fw_size = header[2] | (header[3] << 8) | (header[4] << 16) | (header[5] << 24); + if (seq == 0) { + ota_meta_t meta = { .total_size = fw_size, .stored_size = 0, .last_seq = 0, + .chunk_count = (fw_size + 4095) / 4096, .checksum = {0} }; + meta_save(&meta); + DEBUG_INFO("WIFI", "开始 GD32 固件存储: %u 字节", fw_size); + } + } + + // 继续读剩余数据 + while (received + header_read < req->content_len) { + size_t to_read = req->content_len - received - header_read; + if (to_read > OTA_BLOCK_SIZE) to_read = OTA_BLOCK_SIZE; + + int ret = httpd_req_recv(req, (char *)buf, to_read); + if (ret <= 0) break; + + uint32_t flash_offset = ((received + header_read) / OTA_BLOCK_SIZE) * OTA_BLOCK_SIZE; + esp_err_t err = flash_write_chunk(flash_offset, buf, ret); + if (err == ESP_OK) { + meta_update(flash_offset + ret, (received + header_read) / OTA_BLOCK_SIZE); + } + received += ret; + + uint32_t progress = ((received + header_read) * 100) / req->content_len; + if (progress % 10 == 0) { + DEBUG_INFO("WIFI", "GD32 上传进度: %d / %d (%u%%)", + received + header_read, req->content_len, progress); + } + } + + free(buf); + DEBUG_INFO("WIFI", "GD32 固件存储完成: %d 字节", received + header_read); + + ota_meta_t meta; + meta_load(&meta); + if (meta.stored_size >= meta.total_size) { + s_gd32_storage_done = true; + DEBUG_INFO("WIFI", "GD32 固件已存储,触发转发..."); + wifi_ota_signal_relay(); + } + + const char resp[] = "{\"status\": \"ok\", \"progress\": 100, \"target\": \"gd32\"}"; + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + return ESP_OK; +} + +// HTTP POST /ota/relay 处理器 +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(); + + const char resp[] = "{\"status\": \"ok\", \"message\": \"OTA relay triggered\"}"; + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + + return ESP_OK; +} + +// 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); + + char resp[256]; + int len = snprintf(resp, sizeof(resp), + "{\"total_size\": %lu, \"stored_size\": %lu, \"last_seq\": %lu, " + "\"storage_done\": %s, \"relay_state\": %d}", + (unsigned long)meta.total_size, (unsigned long)meta.stored_size, + (unsigned long)meta.last_seq, + s_gd32_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_gd32_storage_done ? "true" : "false"); + + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, len); + + return ESP_OK; +} + +// 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)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); + + return ESP_OK; +} + +// HTTP POST /can/send 处理器 +// 上位机发送 CAN 帧,经 ESP32 转发到 GD32 +// 请求体: {"ch": 0, "id": 123456, "data": "0102030405060708", "dlc": 8} +// data 为 hex 字符串(可不填,自动用 dlc 决定实际发送长度) +static esp_err_t can_send_handler(httpd_req_t *req) +{ + char buf[256] = {0}; + int ret = httpd_req_recv(req, buf, sizeof(buf) - 1); + if (ret <= 0) { + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "接收数据失败"); + return ESP_FAIL; + } + buf[ret] = '\0'; + + cJSON *root = cJSON_Parse(buf); + if (!root) { + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "JSON 解析失败"); + return ESP_FAIL; + } + + cJSON *ch_item = cJSON_GetObjectItem(root, "ch"); + cJSON *id_item = cJSON_GetObjectItem(root, "id"); + cJSON *data_item = cJSON_GetObjectItem(root, "data"); + cJSON *dlc_item = cJSON_GetObjectItem(root, "dlc"); + + if (!ch_item || !id_item) { + cJSON_Delete(root); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "缺少 ch 或 id 字段"); + return ESP_FAIL; + } + + can_channel_t ch = (can_channel_t)cJSON_GetNumberValue(ch_item); + uint32_t ext_id = (uint32_t)cJSON_GetNumberValue(id_item); + uint8_t dlc = dlc_item ? (uint8_t)cJSON_GetNumberValue(dlc_item) : 0; + + uint8_t tx_data[CAN_MAX_DLC] = {0}; + uint8_t tx_dlc = 0; + + if (data_item && cJSON_IsString(data_item)) { + const char *hex_str = cJSON_GetStringValue(data_item); + size_t hex_len = strlen(hex_str); + for (size_t i = 0; i < hex_len / 2 && i < CAN_MAX_DLC; i++) { + char byte_str[3] = { hex_str[i * 2], hex_str[i * 2 + 1], '\0' }; + tx_data[i] = (uint8_t)strtol(byte_str, NULL, 16); + tx_dlc++; + } + } + + if (tx_dlc == 0 && dlc > 0) { + tx_dlc = (dlc > CAN_MAX_DLC) ? CAN_MAX_DLC : dlc; + } + + cJSON_Delete(root); + + // 发送 CAN 帧到 GD32 + uint8_t resp_data[CAN_MAX_DLC] = {0}; + int resp_len = gd32_can_send(ch, ext_id, tx_data, tx_dlc, + resp_data, sizeof(resp_data), 1000); + + char resp[512]; + if (resp_len >= 0) { + // 将响应 data 转为 hex 字符串 + char resp_hex[CAN_MAX_DLC * 2 + 1] = {0}; + for (int i = 0; i < resp_len; i++) { + sprintf(&resp_hex[i * 2], "%02X", resp_data[i]); + } + snprintf(resp, sizeof(resp), + "{\"status\": \"ok\", \"ch\": %d, \"id\": %lu, \"sent\": %d, \"recv_len\": %d, \"recv\": \"%s\"}", + ch, (unsigned long)ext_id, tx_dlc, resp_len, resp_hex); + } else { + snprintf(resp, sizeof(resp), + "{\"status\": \"error\", \"code\": %d}", resp_len); + } + + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + return ESP_OK; +} + +// HTTP GET /can/status 处理器 +static esp_err_t can_status_handler(httpd_req_t *req) +{ + char resp[128]; + snprintf(resp, sizeof(resp), + "{\"channels\": 3, \"max_dlc\": %d, \"spi_init\": %s}", + CAN_MAX_DLC, + g_spi_device != NULL ? "true" : "false"); + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + return ESP_OK; +} + +// HTTP GET /wifi/status 处理器 +static esp_err_t wifi_status_handler(httpd_req_t *req) +{ + char resp[256]; + char ip_str[16] = "0.0.0.0"; + int8_t rssi = -127; + + if (s_wifi_mode == OTA_WIFI_MODE_STA && s_sta_connected) { + esp_netif_ip_info_t ip_info; + esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (sta_netif && esp_netif_get_ip_info(sta_netif, &ip_info) == ESP_OK) { + snprintf(ip_str, sizeof(ip_str), IPSTR, IP2STR(&ip_info.ip)); + } + wifi_ap_record_t ap_info; + if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) { + rssi = ap_info.rssi; + } + } + + int len = snprintf(resp, sizeof(resp), + "{\"mode\": \"%s\", \"ip\": \"%s\", \"rssi\": %d, \"connected\": %s}", + s_wifi_mode == OTA_WIFI_MODE_AP ? "AP" : "STA", + ip_str, rssi, + (s_wifi_mode == OTA_WIFI_MODE_STA) ? (s_sta_connected ? "true" : "false") : "N/A"); + + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, len); + + return ESP_OK; +} + +// ---------------------------------------- +// 启动 HTTP OTA 服务器 +// ---------------------------------------- +static esp_err_t http_ota_server_start(void) +{ + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.server_port = HTTP_SERVER_PORT; + config.stack_size = HTTP_SERVER_STACK_SIZE; + config.max_uri_handlers = 16; // 默认只有8个槽位,我们有9个端点,不够 + + 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) { + DEBUG_ERR("WIFI", "HTTP 服务器启动失败: %s", esp_err_to_name(err)); + return err; + } + + httpd_uri_t upload_uri = { + .uri = "/ota/upload", + .method = HTTP_POST, + .handler = ota_upload_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &upload_uri); + + httpd_uri_t relay_uri = { + .uri = "/ota/relay", + .method = HTTP_POST, + .handler = ota_relay_trigger_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &relay_uri); + + httpd_uri_t status_uri = { + .uri = "/ota/status", + .method = HTTP_GET, + .handler = ota_status_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &status_uri); + + httpd_uri_t esp32_update_uri = { + .uri = "/ota/update", + .method = HTTP_POST, + .handler = esp32_ota_update_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &esp32_update_uri); + + httpd_uri_t esp32_status_uri = { + .uri = "/ota/esp32_status", + .method = HTTP_GET, + .handler = esp32_ota_status_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &esp32_status_uri); + + httpd_uri_t health_uri = { + .uri = "/health", + .method = HTTP_GET, + .handler = health_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &health_uri); + + httpd_uri_t wifi_status_uri = { + .uri = "/wifi/status", + .method = HTTP_GET, + .handler = wifi_status_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &wifi_status_uri); + + // CAN 帧转发 + httpd_uri_t can_send_uri = { + .uri = "/can/send", + .method = HTTP_POST, + .handler = can_send_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &can_send_uri); + + httpd_uri_t can_status_uri = { + .uri = "/can/status", + .method = HTTP_GET, + .handler = can_status_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &can_status_uri); + + DEBUG_INFO("WIFI", "HTTP 服务器已启动"); + DEBUG_INFO("WIFI", "注册端点: /ota/upload, /ota/relay, /ota/update, /ota/status, /ota/esp32_status, /health, /wifi/status, /can/send, /can/status"); + + return ESP_OK; +} + +// ---------------------------------------- +// 公开 API +// ---------------------------------------- +void wifi_ota_signal_relay(void) +{ + if (s_relay_triggered) { + DEBUG_WARN("WIFI", "转发已经触发过"); + return; + } + + s_relay_triggered = true; + + if (g_ota_dispatch_queue) { + uint32_t msg = 1; + xQueueSend(g_ota_dispatch_queue, &msg, pdMS_TO_TICKS(100)); + DEBUG_INFO("WIFI", "OTA 调度信号已发送到中继任务"); + } +} + +ota_wifi_mode_t wifi_get_mode(void) +{ + return s_wifi_mode; +} + +int8_t wifi_get_rssi(void) +{ + if (s_wifi_mode != OTA_WIFI_MODE_STA || !s_sta_connected) { + return -127; + } + wifi_ap_record_t ap_info; + if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) { + return ap_info.rssi; + } + return -127; +} + +bool wifi_is_connected(void) +{ + return s_sta_connected; +} + +// ---------------------------------------- +// WiFi OTA FreeRTOS 任务 +// ---------------------------------------- +void wifi_ota_task(void *pvParameters) +{ + (void)pvParameters; + + 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_netif_init(); + DEBUG_INFO("WIFI", "网络接口初始化成功"); + + // 创建默认事件循环(必须在 esp_wifi_init 之前) + esp_err_t ev_ret = esp_event_loop_create_default(); + if (ev_ret == ESP_OK) { + DEBUG_INFO("WIFI", "默认事件循环已创建"); + } else if (ev_ret == ESP_ERR_INVALID_STATE) { + DEBUG_INFO("WIFI", "默认事件循环已存在,跳过"); + } else { + DEBUG_ERR("WIFI", "创建事件循环失败: %s", esp_err_to_name(ev_ret)); + } + + // ★ 创建信号量(用于事件驱动等待) + s_sta_connected_sem = xSemaphoreCreateBinary(); + s_sta_got_ip_sem = xSemaphoreCreateBinary(); + if (!s_sta_connected_sem || !s_sta_got_ip_sem) { + DEBUG_ERR("WIFI", "创建信号量失败"); + } + + // ★ 注册 WiFi/IP 事件回调(必须在 esp_wifi_init 之前) + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); + DEBUG_INFO("WIFI", "WiFi/IP 事件回调已注册"); + + // ★ 创建 STA netif(必须在 esp_wifi_init 之前!) + // esp_netif_create_default_wifi_sta() 注册默认 STA 事件处理 + // 如果在 esp_wifi_init() 之后调用,部分内部 handler 不会正确绑定 + esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (sta_netif == NULL) { + sta_netif = esp_netif_create_default_wifi_sta(); + if (sta_netif == NULL) { + DEBUG_ERR("WIFI", "创建 STA netif 失败"); + } else { + DEBUG_INFO("WIFI", "STA netif 已创建"); + } + } else { + DEBUG_INFO("WIFI", "STA netif 已存在,跳过创建"); + } + + // 初始化 WiFi driver(必须在 netif 创建之后) + wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&wifi_cfg)); + DEBUG_INFO("WIFI", "WiFi driver 初始化成功"); + + // STA 优先,失败自动切 AP(事件驱动连接 + 自动重连) + // 注意:CONFIG_WIFI_MODE 是 constexpr,不能用 #if(预处理器不认识 C++ 变量) + if (CONFIG_WIFI_MODE == 1) { + DEBUG_INFO("WIFI", "工作模式: STA (优先)"); + err = wifi_init_sta(); + if (err == ESP_OK) { + char ip_str[16] = {0}; + + // 等待连接成功 + err = wifi_wait_sta_connected(ip_str, sizeof(ip_str)); + if (err == ESP_OK) { + DEBUG_INFO("WIFI", "STA 已连接, IP: %s", ip_str); + } else { + DEBUG_WARN("WIFI", "STA 连接超时,切换到 AP 模式..."); + esp_wifi_stop(); + s_wifi_mode = OTA_WIFI_MODE_AP; + wifi_init_ap(); + } + } + } else { + DEBUG_INFO("WIFI", "工作模式: AP"); + wifi_init_ap(); + } + + // 启动 HTTP 服务器 + err = http_ota_server_start(); + if (err != ESP_OK) { + DEBUG_ERR("WIFI", "HTTP 服务器启动失败"); + } + + DEBUG_INFO("WIFI", "=== WiFi OTA 服务器就绪 ==="); + + // 定期检查 WiFi 状态 + while (1) { + int8_t rssi = wifi_get_rssi(); + if (rssi != -127) { + health_update_from_wifi_rssi(rssi); + + if (rssi < WIFI_RSSI_CRITICAL) { + 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); + } + } + + vTaskDelay(pdMS_TO_TICKS(10000)); + } +} diff --git a/config/partitions.csv b/config/partitions.csv index 6f30c22..4aedb95 100644 --- a/config/partitions.csv +++ b/config/partitions.csv @@ -1,7 +1,8 @@ -# ESP32-C3FH4 OTA Relay - Partition Table +# ESP32-C3FH4 OTA Relay - Partition Table (4MB Flash) # Name, Type, SubType, Offset, Size, Label -otadata, data, ota, 0x9000, 0x2000, -gd32_ota, data, spiffs, 0xB000, 0x40000, -app0, app, ota_0, 0x4B000, 0x330000, -app1, app, ota_1, 0x3DC000, 0x330000, -spiffs, data, spiffs, 0x670000, 0x190000, \ No newline at end of file +nvs, data, nvs, 0x9000, 0x6000, +otadata, data, ota, 0xF000, 0x2000, +gd32_ota, data, spiffs, 0x11000, 0x3F000, +app0, app, ota_0, 0x50000, 0x140000, +app1, app, ota_1, 0x190000, 0x140000, +spiffs, data, spiffs, 0x2D0000, 0x110000, \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 076ad20..77cc109 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -17,6 +17,7 @@ idf_component_register( "monitor" "include" REQUIRES + app_update cjson esp_driver_spi esp_driver_tsens @@ -31,4 +32,5 @@ idf_component_register( nvs_flash freertos mbedtls + bt ) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild deleted file mode 100644 index 0064244..0000000 --- a/main/Kconfig.projbuild +++ /dev/null @@ -1,20 +0,0 @@ -menu "ESP32_COMM Configuration" - - config ESP_WIFI_SSID - string "WiFi SSID" - default "ESP32_OTA_RELAY" - - config ESP_WIFI_PASSWORD - string "WiFi Password" - default "12345678" - - config ESP_WIFI_CHANNEL - int "WiFi Channel" - range 1 13 - default 6 - - config ESP_MAX_STA_CONN - int "Max STA connections" - default 4 - -endmenu diff --git a/main/core/main.cpp b/main/core/main.cpp index 866afed..347b43d 100644 --- a/main/core/main.cpp +++ b/main/core/main.cpp @@ -9,8 +9,8 @@ #include "freertos/task.h" #include "esp_chip_info.h" #include "esp_system.h" -#include "esp_clk_tree.h" #include "esp_netif.h" +#include "esp_event.h" #include "monitor/health_monitor.h" #include "relay/ota_relay.h" @@ -25,23 +25,30 @@ static void status_monitor_task(void *pvParameters); extern "C" void app_main(void) { - // 【关键】在所有任务创建之前初始化网络接口 - // esp_timer 内部依赖 tcpip 线程,health_monitor_task 的 esp_timer_create - // 会在 scheduler 启动后立即执行。如果 esp_netif_init() 没有提前调用, - // tcpip 线程的 mailbox 还未创建,此时 esp_timer 发消息给 tcpip 线程就会崩溃。 - // esp_netif_init() 可以安全调用多次,后续 wifi_ota_task 中的调用是多余的但不报错。 - ESP_ERROR_CHECK(esp_netif_init()); - esp_chip_info_t chip_info; esp_chip_info(&chip_info); - - // 初始化调试日志(UDP 输出到上位机 + UART0 串口) + + // 初始化网络接口 + 事件循环(必须最早) + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 初始化调试日志(UART0 先就绪,UDP socket 延迟到首次发送时创建) + // 必须在 wifi_early_init 之前,这样 WiFi 初始化日志也能输出到上位机 debug_log_init(); + + // ★ WiFi 提前初始化(调度器启动前) + // 包括:NVS → netif 创建 → event handler 注册 → WiFi driver init → 配置 → connect + // 连接尝试立即开始,事件排队等调度器启动后处理 + bool wifi_sta_ok = wifi_early_init(); + + health_monitor_init(); + DEBUG_INFO("MAIN", "健康监控状态已初始化"); DEBUG_INFO("MAIN", "========================================"); DEBUG_INFO("MAIN", "ESP32-C3 OTA Relay v1.0 启动"); DEBUG_INFO("MAIN", "Chip: %s, Rev %d", CONFIG_IDF_TARGET, chip_info.revision); DEBUG_INFO("MAIN", "Free heap: %lu bytes", esp_get_free_heap_size()); DEBUG_INFO("MAIN", "CPU Freq: %d MHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ); + DEBUG_INFO("MAIN", "WiFi: %s", wifi_sta_ok ? "STA 连接中" : "将使用 AP 模式"); DEBUG_INFO("MAIN", "========================================"); // 健康监控任务(温度 + 电压 + WiFi RSSI) diff --git a/main/idf_component.yml b/main/idf_component.yml deleted file mode 100644 index d4e300f..0000000 --- a/main/idf_component.yml +++ /dev/null @@ -1,2 +0,0 @@ -## IDF Component Manager Manifest File -dependencies: {} diff --git a/main/include/app_config.h b/main/include/app_config.h index 359ed4c..663bdcd 100644 --- a/main/include/app_config.h +++ b/main/include/app_config.h @@ -7,12 +7,17 @@ #pragma once #include +// ============================================================ +// 固件版本 +// ============================================================ +inline constexpr const char *FW_VERSION = "0.0.6"; + // ============================================================ // WiFi 工作模式选择 // ============================================================ // 0 = AP 模式(设备当热点) // 1 = STA 模式(连接路由器) -inline constexpr uint8_t CONFIG_WIFI_MODE = 0; +inline constexpr uint8_t CONFIG_WIFI_MODE = 1; // ============================================================ // WiFi STA 模式配置(连接路由器) @@ -20,16 +25,16 @@ inline constexpr uint8_t CONFIG_WIFI_MODE = 0; inline constexpr const char* WIFI_STA_SSID = "004舰桥"; inline constexpr const char* WIFI_STA_PASSWORD = "q13362875622"; inline constexpr uint32_t WIFI_STA_CONNECT_TIMEOUT_MS = 30000; +inline constexpr uint8_t WIFI_STA_MAX_RETRY = 5; // 最大重连次数,超过后切换 AP 模式 // STA 静态 IP -inline constexpr uint8_t WIFI_STA_USE_STATIC_IP = 1; // 设为 1 启用静态 IP +inline constexpr uint8_t WIFI_STA_USE_STATIC_IP = 0; // 先关闭静态 IP,使用 DHCP 排查连接问题 -#if WIFI_STA_USE_STATIC_IP -inline constexpr const char* WIFI_STA_STATIC_IP = "192.168.1.100"; -inline constexpr const char* WIFI_STA_STATIC_GW = "192.168.1.1"; +// 静态 IP 配置(始终定义,由 WIFI_STA_USE_STATIC_IP 在运行时决定是否使用) +inline constexpr const char* WIFI_STA_STATIC_IP = "192.168.31.32"; +inline constexpr const char* WIFI_STA_STATIC_GW = "192.168.31.1"; inline constexpr const char* WIFI_STA_STATIC_NETMASK = "255.255.255.0"; -inline constexpr const char* WIFI_STA_STATIC_DNS = "192.168.1.1"; -#endif +inline constexpr const char* WIFI_STA_STATIC_DNS = "192.168.31.1"; // ============================================================ // WiFi AP 模式配置(设备当热点) @@ -54,8 +59,8 @@ inline constexpr size_t OTA_MAX_FIRMWARE_SIZE = 2 * 1024 * 1024; // 2MB // ============================================================ // 健康监控阈值 // ============================================================ -inline constexpr int32_t WIFI_RSSI_CRITICAL = -75; -inline constexpr int32_t WIFI_RSSI_WARNING = -65; +inline constexpr int32_t WIFI_RSSI_CRITICAL = -85; +inline constexpr int32_t WIFI_RSSI_WARNING = -75; inline constexpr int32_t TEMP_WARNING = 80; inline constexpr int32_t TEMP_CRITICAL = 100; inline constexpr size_t HEAP_WARNING_MIN = 10240; diff --git a/main/monitor/debug_log.cpp b/main/monitor/debug_log.cpp index 1c7a56d..7c3dec6 100644 --- a/main/monitor/debug_log.cpp +++ b/main/monitor/debug_log.cpp @@ -1,11 +1,17 @@ /* * debug_log.c - WiFi 调试日志输出实现 * - * 通过 UDP socket 发送调试日志到上位机 + * 通过 UDP socket 将调试日志发送到上位机 * 上位机需监听 : * * 支持双通道输出:UDP + UART0 串口 * UART0: TX=GPIO21, RX=GPIO20, 115200 波特率 + * + * 时序说明: + * esp_netif_init() 创建 tcpip 线程后才可安全使用 socket + * 本模块在首次 debug_log_send() 时才创建 socket(延迟创建) + * WiFi 连接前 sendto() 会失败(无路由),日志仅走 UART + * WiFi 连接后 UDP 立即生效,无需额外操作 */ #include #include @@ -13,6 +19,7 @@ #include #include #include "freertos/task.h" +#include "freertos/semphr.h" #include "esp_log.h" #include "esp_err.h" #include "driver/uart.h" @@ -27,6 +34,116 @@ static int s_udp_sock = -1; static struct sockaddr_in s_debug_addr; static bool s_initialized = false; +// ============================================================ +// 日志环形缓冲区(供 HTTP /logs 拉取) +// ============================================================ +#define LOG_RING_SLOTS 64 +#define LOG_RING_SIZE 256 +static char s_log_ring[LOG_RING_SLOTS][LOG_RING_SIZE]; +static int s_log_ring_lens[LOG_RING_SLOTS]; +static int s_log_ring_head = 0; // 下次写入位置 +static int s_log_ring_count = 0; // 已存条数(超过 LOG_RING_SLOTS 后不再增长,覆盖旧数据) +static SemaphoreHandle_t s_log_ring_mutex = NULL; + +// 获取日志缓冲区中的条数 +int debug_log_ring_count(void) +{ + if (!s_log_ring_mutex) return 0; + xSemaphoreTake(s_log_ring_mutex, portMAX_DELAY); + int count = s_log_ring_count; + xSemaphoreGive(s_log_ring_mutex); + return count; +} + +// 读取并清空日志缓冲区,返回 JSON 数组字符串 +// 调用者负责 free 返回值 +char *debug_log_ring_drain_json(int *out_len) +{ + if (!s_log_ring_mutex) { + *out_len = 0; + return NULL; + } + + xSemaphoreTake(s_log_ring_mutex, portMAX_DELAY); + + int count = s_log_ring_count; + if (count == 0) { + xSemaphoreGive(s_log_ring_mutex); + *out_len = 0; + return NULL; + } + + // 估算 JSON 大小:每条 ~280 字节(转义 + JSON 包装) + size_t buf_size = (size_t)count * 280 + 16; + char *json = (char *)malloc(buf_size); + if (!json) { + xSemaphoreGive(s_log_ring_mutex); + *out_len = 0; + return NULL; + } + + int pos = 0; + json[pos++] = '['; + + // 从最旧的开始读 + int start = (count < LOG_RING_SLOTS) ? 0 : s_log_ring_head; + for (int i = 0; i < count && pos < (int)buf_size - 200; i++) { + int idx = (start + i) % LOG_RING_SLOTS; + int len = s_log_ring_lens[idx]; + if (len <= 0) continue; + + if (i > 0) json[pos++] = ','; + + // JSON 转义日志内容 + pos += snprintf(json + pos, buf_size - pos, "\""); + for (int j = 0; j < len && pos < (int)buf_size - 10; j++) { + char c = s_log_ring[idx][j]; + if (c == '"' || c == '\\') { + json[pos++] = '\\'; + json[pos++] = c; + } else if (c == '\n') { + json[pos++] = '\\'; + json[pos++] = 'n'; + } else if (c >= 32) { + json[pos++] = c; + } + } + pos += snprintf(json + pos, buf_size - pos, "\""); + } + + json[pos++] = ']'; + json[pos] = '\0'; + + // 清空缓冲区 + s_log_ring_head = 0; + s_log_ring_count = 0; + + xSemaphoreGive(s_log_ring_mutex); + + *out_len = pos; + return json; +} + +// 写入一条日志到环形缓冲区 +static void log_ring_push(const char *data, int len) +{ + if (!s_log_ring_mutex || len <= 0) return; + + xSemaphoreTake(s_log_ring_mutex, portMAX_DELAY); + + int copy_len = len; + if (copy_len >= LOG_RING_SIZE) copy_len = LOG_RING_SIZE - 1; + + memcpy(s_log_ring[s_log_ring_head], data, copy_len); + s_log_ring[s_log_ring_head][copy_len] = '\0'; + s_log_ring_lens[s_log_ring_head] = copy_len; + + s_log_ring_head = (s_log_ring_head + 1) % LOG_RING_SLOTS; + if (s_log_ring_count < LOG_RING_SLOTS) s_log_ring_count++; + + xSemaphoreGive(s_log_ring_mutex); +} + // UART0 状态 static bool s_uart_initialized = false; static uart_port_t s_uart_port = UART_NUM_0; @@ -95,37 +212,37 @@ esp_err_t uart_debug_send(const uint8_t *data, size_t len) // UDP 调试日志 // ============================================================ -// 初始化 UDP socket(注意:socket 创建延迟到 debug_log_send 首次调用时) -// 因为 esp_netif_init() 会在 wifi_ota_task 里调用,提前创建 socket 会导致 tcpip 线程未就绪而崩溃 +// 初始化(UART 立即可用,UDP socket 延迟到首次发送时创建) esp_err_t debug_log_init(void) { if (s_initialized) { return ESP_OK; } - // 初始化 UART0(不需要网络) uart_debug_init(); - // 延迟创建 socket:先只初始化目标地址,socket 在 debug_log_send 首次发 UDP 时创建 + // 日志环形缓冲区互斥锁 + s_log_ring_mutex = xSemaphoreCreateMutex(); + + // 目标地址:单播到上位机 memset(&s_debug_addr, 0, sizeof(s_debug_addr)); s_debug_addr.sin_family = AF_INET; s_debug_addr.sin_port = htons(DEBUG_LOG_PORT); s_debug_addr.sin_addr.s_addr = inet_addr(DEBUG_LOG_IP); s_initialized = true; - ESP_LOGI(TAG, "调试日志已初始化(UDP socket 延迟创建),上位机 IP=%s:%d", DEBUG_LOG_IP, DEBUG_LOG_PORT); + ESP_LOGI(TAG, "调试日志已初始化,上位机 %s:%d", DEBUG_LOG_IP, DEBUG_LOG_PORT); return ESP_OK; } -// 延迟创建 UDP socket(仅在首次发送 UDP 时调用) +// 延迟创建 UDP socket(首次发送时调用) static esp_err_t ensure_udp_socket(void) { if (s_udp_sock >= 0) { - return ESP_OK; // 已创建 + return ESP_OK; } - // 创建 UDP socket s_udp_sock = socket(AF_INET, SOCK_DGRAM, 0); if (s_udp_sock < 0) { ESP_LOGE(TAG, "创建 UDP socket 失败"); @@ -136,49 +253,39 @@ static esp_err_t ensure_udp_socket(void) return ESP_OK; } -// 发送原始数据到上位机(UDP + UART 双通道) +// 发送原始数据(UDP 单播 + UART 双通道) esp_err_t debug_log_send(const uint8_t *data, size_t len) { esp_err_t udp_ret = ESP_FAIL; esp_err_t uart_ret = ESP_FAIL; - // UART 通道发送 + // UART 通道 if (s_uart_initialized) { uart_ret = uart_debug_send(data, len); } - // UDP 通道发送(延迟创建 socket) + // UDP 通道(WiFi 未连接时 sendto 失败,静默跳过) if (s_initialized) { - // 首次 UDP 发送前才创建 socket if (s_udp_sock < 0) { - if (ensure_udp_socket() != ESP_OK) { - // socket 创建失败,走 UART 通道 - } else { - udp_ret = ESP_OK; // 标记为已就绪 - } + ensure_udp_socket(); } if (s_udp_sock >= 0) { - if (len > 1024) { - len = 1024; // 限制单次发送大小 - } - - int ret = sendto(s_udp_sock, data, len, 0, + size_t send_len = len > 1024 ? 1024 : len; + int ret = sendto(s_udp_sock, data, send_len, 0, (struct sockaddr *)&s_debug_addr, sizeof(s_debug_addr)); - - if (ret < 0) { - udp_ret = ESP_FAIL; - } else { + if (ret >= 0) { udp_ret = ESP_OK; } } } - // 至少一个通道成功即返回成功 + // 同时写入环形缓冲区(供 HTTP /logs 拉取) + log_ring_push((const char *)data, (int)len); + if (udp_ret == ESP_OK || uart_ret == ESP_OK) { return ESP_OK; } - return ESP_FAIL; } @@ -193,7 +300,6 @@ void debug_log(debug_log_level_t level, const char *tag, const char *fmt, ...) return; } - // 格式化日志头 char prefix[32]; const char *level_str; switch (level) { @@ -205,17 +311,14 @@ void debug_log(debug_log_level_t level, const char *tag, const char *fmt, ...) } snprintf(prefix, sizeof(prefix), "[%s][%s]", level_str, tag); - // 格式化消息体 va_list args; va_start(args, fmt); char msg[512]; vsnprintf(msg, sizeof(msg), fmt, args); va_end(args); - // 组装完整日志帧 char log_buf[600]; int total = snprintf(log_buf, sizeof(log_buf), "%s %s\n", prefix, msg); - // 发送(末尾 \n 会被保留) debug_log_send((const uint8_t *)log_buf, total); -} \ No newline at end of file +} diff --git a/main/monitor/debug_log.h b/main/monitor/debug_log.h index bfcf8db..d96f9b7 100644 --- a/main/monitor/debug_log.h +++ b/main/monitor/debug_log.h @@ -1,8 +1,8 @@ /* * debug_log.h - WiFi 调试日志输出 * - * 通过 UDP socket 将调试信息发送到上位机 - * 上位机监听 / 接收日志 + * 通过 UDP socket 将调试日志发送到上位机 + * 上位机监听 接收日志 * * 支持双通道输出:UDP + UART0 串口 * UART0: TX=GPIO21, RX=GPIO20, 115200 波特率 @@ -50,6 +50,10 @@ esp_err_t debug_log_send(const uint8_t *data, size_t len); // 格式化日志输出(类似 printf) void debug_log(debug_log_level_t level, const char *tag, const char *fmt, ...); +// 日志环形缓冲区(供 HTTP /logs 拉取) +int debug_log_ring_count(void); +char *debug_log_ring_drain_json(int *out_len); // 调用者 free + // 宏定义方便调用 #define DEBUG_ERR(tag, fmt, ...) debug_log(DEBUG_LOG_ERR, tag, fmt, ##__VA_ARGS__) #define DEBUG_WARN(tag, fmt, ...) debug_log(DEBUG_LOG_WARN, tag, fmt, ##__VA_ARGS__) diff --git a/main/monitor/health_monitor.cpp b/main/monitor/health_monitor.cpp index ee9b967..7cabfb8 100644 --- a/main/monitor/health_monitor.cpp +++ b/main/monitor/health_monitor.cpp @@ -19,6 +19,8 @@ health_state_t g_health_state = SYS_NORMAL; static SemaphoreHandle_t g_health_mutex = NULL; static temperature_sensor_handle_t s_temp_handle = NULL; +static float s_last_temperature = 0.0f; +static float s_last_voltage = 3.30f; // ---------------------------------------- // 健康状态管理 @@ -44,6 +46,16 @@ health_state_t health_get_current(void) return state; } +float health_get_last_temperature(void) +{ + return s_last_temperature; +} + +float health_get_last_voltage(void) +{ + return s_last_voltage; +} + // ---------------------------------------- // 温度监控(定时器回调) // ---------------------------------------- @@ -56,7 +68,7 @@ static void temp_monitor_callback(void *arg) return; } - DEBUG_DBG("TEMP", "芯片温度: %.1f°C", temp); + s_last_temperature = temp; if (temp >= TEMP_CRITICAL) { g_health_state = SYS_SAFE_SHUTDOWN; @@ -77,7 +89,7 @@ static void temp_monitor_callback(void *arg) static void voltage_monitor_callback(void *arg) { float voltage = 3.30f; // ESP32-C3 无内置电压传感器,使用估算 - DEBUG_DBG("VOLT", "VDD 电压: %.2fV (估算)", voltage); + s_last_voltage = voltage; if (voltage < 2.3f) { g_health_state = SYS_SAFE_SHUTDOWN; @@ -89,8 +101,6 @@ static void voltage_monitor_callback(void *arg) DEBUG_WARN("VOLT", "警告: 电压 %.2fV < 2.5V", voltage); DEBUG_WARN("VOLT", "健康状态变更为: SYS_WARNING"); } - } else { - DEBUG_INFO("VOLT", "电压正常: %.2fV", voltage); } } @@ -111,7 +121,7 @@ void health_monitor_task(void *pvParameters) DEBUG_INFO("MON", "温度传感器已启用 (范围 20°C ~ 80°C)"); } - // 定时器,每5秒读取一次温度 + // 定时器,每1秒读取一次温度 esp_timer_handle_t temp_timer; esp_timer_create_args_t timer_args = {}; timer_args.callback = &temp_monitor_callback; @@ -120,40 +130,35 @@ void health_monitor_task(void *pvParameters) 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, 5 * 1000000); // 5秒 + esp_timer_start_periodic(temp_timer, 1 * 1000000); // 1秒 - DEBUG_INFO("MON", "温度监控定时器已启动 (间隔 5 秒)"); + DEBUG_INFO("MON", "温度监控定时器已启动 (间隔 1 秒)"); // 启动时检查一次电压 voltage_monitor_callback(NULL); - // 每5秒打印一次健康状态 - uint32_t loop_count = 0; + // 每1秒刷新一次估算电压 + esp_timer_handle_t volt_timer; + esp_timer_create_args_t volt_timer_args = {}; + volt_timer_args.callback = &voltage_monitor_callback; + volt_timer_args.arg = nullptr; + volt_timer_args.name = "volt_monitor"; + volt_timer_args.dispatch_method = ESP_TIMER_TASK; + volt_timer_args.skip_unhandled_events = false; + esp_timer_create(&volt_timer_args, &volt_timer); + esp_timer_start_periodic(volt_timer, 1 * 1000000); // 1秒 + DEBUG_INFO("MON", "电压监控定时器已启动 (间隔 1 秒)"); + + // 保活循环:定时器由 esp_timer 任务驱动,此任务只需保持存活 + // 状态汇报已由 status_monitor_task 负责,此处只在异常时告警 while (1) { - loop_count++; - uint32_t free_heap = esp_get_free_heap_size(); - - const char *state_str; - switch (g_health_state) { - case SYS_NORMAL: state_str = "正常"; break; - case SYS_WARNING: state_str = "警告"; break; - case SYS_CRITICAL: state_str = "危险"; break; - case SYS_SAFE_SHUTDOWN: state_str = "安全关机"; break; - default: state_str = "未知"; break; - } - - DEBUG_INFO("MON", "--- 健康状态 #%lu ---", (unsigned long)loop_count); - DEBUG_INFO("MON", "健康状态: %s (%d)", state_str, g_health_state); - DEBUG_INFO("MON", "空闲堆: %lu 字节", (unsigned long)free_heap); - - // 堆内存警告 if (free_heap < HEAP_WARNING_MIN) { DEBUG_WARN("MON", "空闲堆内存不足: %lu < %d", (unsigned long)free_heap, HEAP_WARNING_MIN); } - - DEBUG_INFO("MON", "==================="); - + if (g_health_state >= SYS_CRITICAL) { + DEBUG_ERR("MON", "健康状态危险: %d", g_health_state); + } vTaskDelay(pdMS_TO_TICKS(5000)); } } diff --git a/main/monitor/health_monitor.h b/main/monitor/health_monitor.h index 34574c5..d8ea366 100644 --- a/main/monitor/health_monitor.h +++ b/main/monitor/health_monitor.h @@ -35,3 +35,5 @@ health_status_t health_check_before_ota(void); void health_log_event(const char *event, int value); health_state_t health_get_current(void); health_status_t health_update_from_wifi_rssi(int8_t rssi); +float health_get_last_temperature(void); +float health_get_last_voltage(void); diff --git a/main/relay/ota_relay.cpp b/main/relay/ota_relay.cpp index ca3bd8c..405be3a 100644 --- a/main/relay/ota_relay.cpp +++ b/main/relay/ota_relay.cpp @@ -40,7 +40,7 @@ esp_err_t meta_load(ota_meta_t *meta) FILE *f = fopen(META_FILE, "r"); if (!f) { - DEBUG_WARN("OTA", "元数据文件不存在,返回默认值"); + // 文件不存在是正常状态(首次使用,未刷过 GD32) return ESP_OK; } diff --git a/main/server/ble_ota.cpp b/main/server/ble_ota.cpp index 14abf46..c617edb 100644 --- a/main/server/ble_ota.cpp +++ b/main/server/ble_ota.cpp @@ -1,99 +1,542 @@ /* - * ble_ota.c - BLE OTA GATT 服务器实现 + * ble_ota.cpp - BLE OTA GATT 服务器实现 (ESP-IDF 6.0 NimBLE) * T5.1 - T5.5 - * - * 注意: ESP-IDF 6.0 中蓝牙组件有较大变化 - * 此文件暂时提供空实现,待 ESP-IDF 6.0 蓝牙 API 稳定后再适配 + * + * 通过 BLE GATT 接收上位机固件,存储到 Flash (gd32_ota 分区), + * 接收完成后触发 OTA 中继任务转发到 GD32。 + * + * GATT 服务: + * Service UUID: 0xFFFF + * - CTRL (0x0001, Write): 写入 0xF7 触发中继 + * - DATA_IN (0x0002, Write): 接收固件数据块 + * - DATA_OUT (0x0003, Notify): 推送 GD32 响应 + * - VERSION (0x0004, Read): 固件版本 */ #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" +#include "freertos/queue.h" #include "esp_err.h" +// NimBLE 协议栈 +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/ble_gap.h" +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" + +#include "app_config.h" #include "ble_ota.h" #include "ota_relay.h" #include "health_monitor.h" #include "monitor/debug_log.h" -static bool s_ble_connected = false; +#define TAG "BLE_OTA" -/* ESP-IDF 6.0: BLE OTA 功能暂时禁用,以下函数保留供后续适配使用 */ -#if 0 -// 处理写入控制点 -static void handle_ctrl_point_write(uint8_t *data, size_t len) +// ============================================================ +// 静态状态 +// ============================================================ + +static bool s_ble_ready = false; // NimBLE 同步完成 +static bool s_ble_connected = false; // GATT 客户端已连接 +static uint16_t s_conn_handle = BLE_HS_CONN_HANDLE_NONE; +static uint16_t s_data_out_val_handle = 0; // DATA_OUT 值句柄 (供通知用) + +// ============================================================ +// NimBLE 工具: 从 mbuf 读取原始数据 +// ============================================================ +static int ble_ota_mbuf_to_buf(struct os_mbuf *om, uint8_t *buf, size_t buf_len) { - if (len < 1) return; + if (!om || !buf) return -1; + uint16_t om_len = OS_MBUF_PKTLEN(om); + uint16_t copy_len = (om_len > buf_len) ? (uint16_t)buf_len : om_len; + os_mbuf_copydata(om, 0, copy_len, buf); + return (int)copy_len; +} - uint8_t cmd = data[0]; - DEBUG_DBG("BLE", "控制点写入: cmd=0x%02X, len=%d", cmd, len); +// ============================================================ +// GATT 访问回调 +// ============================================================ - if (cmd == 0xF7 && s_ble_connected) { +/* + * CTRL (0x0001) - Write + * 写入 0xF7 触发 OTA 中继 + */ +static int ble_ota_ctrl_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + (void)conn_handle; + (void)attr_handle; + (void)arg; + + if (ctxt->op != BLE_GATT_ACCESS_OP_WRITE_CHR) { + return BLE_ATT_ERR_REQ_NOT_SUPPORTED; + } + + uint8_t buf[4] = {0}; + int len = ble_ota_mbuf_to_buf(ctxt->om, buf, sizeof(buf)); + if (len < 1) { + DEBUG_WARN(TAG, "CTRL 数据为空"); + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + DEBUG_INFO(TAG, "CTRL 写入: cmd=0x%02X", buf[0]); + + if (buf[0] == 0xF7) { + // 检查固件是否存储完毕 ota_meta_t meta; - meta_load(&meta); - if (meta.stored_size >= meta.total_size) { + esp_err_t err = meta_load(&meta); + if (err == ESP_OK && + meta.total_size > 0 && + meta.stored_size >= meta.total_size) { + DEBUG_INFO(TAG, "固件就绪 (%" PRIu32 " / %" PRIu32 " 字节),触发中继", + meta.stored_size, meta.total_size); ble_ota_signal_relay(); + } else { + DEBUG_WARN(TAG, "固件未就绪, 未触发中继 (stored=%" PRIu32 ", total=%" PRIu32 ")", + meta.stored_size, meta.total_size); } } + + return 0; // BLE_ATT_ERR_OK 在 NimBLE 中就是 0 } -// 处理写入数据输入(大固件分块) -static void handle_data_in_write(uint8_t *data, size_t len) +/* + * DATA_IN (0x0002) - Write + * 数据块格式: + * [0] cmd (0x00=数据) + * [1-2] seq uint16 LE - 分块序号 + * [3-6] total_size uint32 LE - 固件总大小 (仅 seq=0 时有效) + * [7..n-4] payload 固件数据 + * [n-4..n] crc 校验 (预留) + */ +static int ble_ota_data_in_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) { - if (len < 7) return; + (void)conn_handle; + (void)attr_handle; + (void)arg; - uint16_t seq = data[1] | (data[2] << 8); - uint32_t total_size = data[3] | (data[4] << 8) | (data[5] << 16) | (data[6] << 24); - - if (seq == 0 && total_size > 0) { - ota_meta_t meta = { - .total_size = total_size, - .stored_size = 0, - .last_seq = 0, - .chunk_count = (total_size + 4095) / 4096 - }; - meta_save(&meta); - DEBUG_INFO("BLE", "开始固件存储: %" PRIu32 " 字节", total_size); + if (ctxt->op != BLE_GATT_ACCESS_OP_WRITE_CHR) { + return BLE_ATT_ERR_REQ_NOT_SUPPORTED; } + uint8_t buf[BLE_MTU_SIZE] = {0}; + int recv_len = ble_ota_mbuf_to_buf(ctxt->om, buf, sizeof(buf)); + + if (recv_len < 12) { + DEBUG_WARN(TAG, "DATA_IN 数据太短: %d 字节 (最少 12)", recv_len); + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + // 解析包头 + uint8_t cmd = buf[0]; + uint16_t seq = (uint16_t)(buf[1] | (buf[2] << 8)); + uint32_t total_size = (uint32_t)(buf[3] | (buf[4] << 8) | + (buf[5] << 16) | (buf[6] << 24)); + size_t data_offset = 7; - size_t data_len = len - data_offset - 4; + size_t data_len = (size_t)recv_len - data_offset; - uint32_t flash_offset = seq * 4096; - esp_err_t err = flash_write_chunk(flash_offset, &data[data_offset], data_len); - if (err != ESP_OK) { - DEBUG_ERR("BLE", "Flash 写入失败 at seq %" PRIu16, seq); + // 尾 4 字节 CRC 预留,实际 payload = data_len - 4 + if (data_len < 4) { + DEBUG_WARN(TAG, "DATA_IN 负载不足: data_len=%zu", data_len); + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + data_len -= 4; // 减去尾部 CRC 预留 + + DEBUG_DBG(TAG, "DATA_IN: cmd=0x%02X seq=%u total=%" PRIu32 " payload=%zu", + cmd, seq, total_size, data_len); + + // --- 首个分块: 创建存储元数据 --- + if (seq == 0 && total_size > 0) { + if (total_size > OTA_MAX_FIRMWARE_SIZE) { + DEBUG_ERR(TAG, "固件太大: %" PRIu32 " > %zu", + total_size, OTA_MAX_FIRMWARE_SIZE); + return BLE_ATT_ERR_UNLIKELY; + } + + ota_meta_t meta = {}; + meta.total_size = total_size; + meta.stored_size = 0; + meta.last_seq = 0; + meta.chunk_count = (total_size + (OTA_BLOCK_SIZE - 1)) / OTA_BLOCK_SIZE; + + esp_err_t err = meta_save(&meta); + if (err != ESP_OK) { + DEBUG_ERR(TAG, "元数据保存失败"); + return BLE_ATT_ERR_UNLIKELY; + } + + DEBUG_INFO(TAG, "固件存储开始: total=%" PRIu32 " chunk_count=%" PRIu32, + meta.total_size, meta.chunk_count); } - meta_update(flash_offset + data_len, seq); + // --- 写入 Flash --- + uint32_t flash_offset = seq * OTA_BLOCK_SIZE; + esp_err_t err = flash_write_chunk(flash_offset, &buf[data_offset], data_len); + if (err != ESP_OK) { + DEBUG_ERR(TAG, "Flash 写入失败: seq=%u offset=%" PRIu32 " err=%s", + seq, flash_offset, esp_err_to_name(err)); + return BLE_ATT_ERR_UNLIKELY; + } - DEBUG_DBG("BLE", "已存储分块 %" PRIu16 ", offset=%" PRIu32, seq, flash_offset); + // --- 更新元数据 --- + err = meta_update(flash_offset + data_len, seq); + if (err != ESP_OK) { + DEBUG_WARN(TAG, "元数据更新失败 (seq=%u)", seq); + } + // --- 检查是否接收完毕 --- ota_meta_t meta; - meta_load(&meta); - if (meta.stored_size >= meta.total_size) { - DEBUG_INFO("BLE", "全部固件已存储,触发转发"); - ble_ota_signal_relay(); + if (meta_load(&meta) == ESP_OK && + meta.total_size > 0 && + meta.stored_size >= meta.total_size) { + DEBUG_INFO(TAG, "★ 固件接收完毕: %" PRIu32 " / %" PRIu32 " 字节 (共 %u 块)", + meta.stored_size, meta.total_size, seq + 1); + } + + return 0; +} + +/* + * VERSION (0x0004) - Read + * 返回固件版本字符串 + */ +static int ble_ota_version_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + (void)conn_handle; + (void)attr_handle; + (void)arg; + + if (ctxt->op != BLE_GATT_ACCESS_OP_READ_CHR) { + return BLE_ATT_ERR_REQ_NOT_SUPPORTED; + } + + const char *version = "1.0.0"; + int rc = os_mbuf_append(ctxt->om, version, strlen(version)); + return (rc == 0) ? 0 : BLE_ATT_ERR_UNLIKELY; +} + +/* + * DATA_OUT (0x0003) - Notify only + * 访问回调不做读写处理,通知由 ble_ota_notify_response() 发送 + */ +static int ble_ota_data_out_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + (void)conn_handle; + (void)attr_handle; + (void)ctxt; + (void)arg; + return 0; +} + +// ============================================================ +// GATT 服务定义 +// ============================================================ + +// BLE_UUID16_DECLARE 在 C++ 中产生 "taking address of rvalue" 编译错误。 +// ESP-IDF 6.0 NimBLE 的 C++ 兼容写法: 先定义 static ble_uuid16_t 变量, 再取 .u 地址。 +static const ble_uuid16_t GATT_SVC_UUID = BLE_UUID16_INIT(BLE_OTA_SERVICE_UUID); +static const ble_uuid16_t GATT_CTRL_UUID = BLE_UUID16_INIT(BLE_OTA_CTRL_UUID); +static const ble_uuid16_t GATT_DATA_IN_UUID = BLE_UUID16_INIT(BLE_OTA_DATA_IN_UUID); +static const ble_uuid16_t GATT_DATA_OUT_UUID = BLE_UUID16_INIT(BLE_OTA_DATA_OUT_UUID); +static const ble_uuid16_t GATT_VERSION_UUID = BLE_UUID16_INIT(BLE_OTA_VERSION_UUID); + +// NimBLE C 结构体在 C++ designated initializer 不能显式初始化全部字段。 +// 用 pragma 局部关闭 -Wmissing-field-initializers 警告。 +#ifdef __cplusplus +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +static const struct ble_gatt_chr_def gatt_ota_chrs[] = { + { + .uuid = &GATT_CTRL_UUID.u, + .access_cb = ble_ota_ctrl_access, + .flags = BLE_GATT_CHR_F_WRITE, + }, + { + .uuid = &GATT_DATA_IN_UUID.u, + .access_cb = ble_ota_data_in_access, + .flags = BLE_GATT_CHR_F_WRITE, + }, + { + .uuid = &GATT_DATA_OUT_UUID.u, + .access_cb = ble_ota_data_out_access, + .flags = BLE_GATT_CHR_F_NOTIFY, + .val_handle = &s_data_out_val_handle, + }, + { + .uuid = &GATT_VERSION_UUID.u, + .access_cb = ble_ota_version_access, + .flags = BLE_GATT_CHR_F_READ, + }, + {} // 终止符 +}; + +static const struct ble_gatt_svc_def gatt_ota_svcs[] = { + { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = &GATT_SVC_UUID.u, + .characteristics = (struct ble_gatt_chr_def *)gatt_ota_chrs, + }, + {} // 终止符 +}; + +#ifdef __cplusplus +#pragma GCC diagnostic pop +#endif + +// ============================================================ +// GAP 事件回调 +// ============================================================ + +static int ble_ota_gap_event(struct ble_gap_event *event, void *arg) +{ + (void)arg; + + switch (event->type) { + + case BLE_GAP_EVENT_CONNECT: + if (event->connect.status == 0) { + // 连接成功 + s_ble_connected = true; + s_conn_handle = event->connect.conn_handle; + DEBUG_INFO(TAG, "BLE 客户端已连接: handle=%d", s_conn_handle); + } else { + DEBUG_WARN(TAG, "BLE 连接失败: status=%d", event->connect.status); + s_ble_connected = false; + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + DEBUG_INFO(TAG, "BLE 客户端已断开: reason=%d", + event->disconnect.reason); + s_ble_connected = false; + s_conn_handle = BLE_HS_CONN_HANDLE_NONE; + // 恢复广播以接受新连接 + ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, + NULL, ble_ota_gap_event, NULL); + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + DEBUG_INFO(TAG, "广播周期结束,重新开始"); + ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, + NULL, ble_ota_gap_event, NULL); + return 0; + + case BLE_GAP_EVENT_SUBSCRIBE: + DEBUG_INFO(TAG, "CCC 描述符更新: conn=%d attr=%d notify=%d indicate=%d", + event->subscribe.conn_handle, + event->subscribe.attr_handle, + event->subscribe.cur_notify, + event->subscribe.cur_indicate); + return 0; + + case BLE_GAP_EVENT_MTU: + DEBUG_INFO(TAG, "MTU 协商: conn=%d mtu=%d", + event->mtu.conn_handle, event->mtu.value); + return 0; + + default: + return 0; } } -#endif /* ESP_IDF_COMPILATION */ -// 启动 BLE GATT 服务器 -// 注意: 此函数在 ESP-IDF 6.0 中暂时返回 ESP_ERR_NOT_SUPPORTED +// ============================================================ +// BLE 广播 +// ============================================================ + +static void ble_ota_start_advertising(void) +{ + uint8_t adv_data[31] = {0}; + int adv_pos = 0; + + // AD Flags: LE General Discoverable + BR/EDR Not Supported + adv_data[adv_pos++] = 0x02; // 长度 + adv_data[adv_pos++] = 0x01; // 类型 = Flags + adv_data[adv_pos++] = 0x06; // 值 + + // Complete Local Name + const char *name = BLE_DEVICE_NAME; + size_t name_len = strlen(name); + if (name_len > 29 - adv_pos - 2) { + name_len = 29 - adv_pos - 2; // 截断以适配广播包 + } + adv_data[adv_pos++] = (uint8_t)(name_len + 1); + adv_data[adv_pos++] = 0x09; // 类型 = Complete Local Name + memcpy(&adv_data[adv_pos], name, name_len); + adv_pos += name_len; + + int rc = ble_gap_adv_set_data(adv_data, adv_pos); + if (rc != 0) { + DEBUG_ERR(TAG, "设置广播数据失败: %d", rc); + return; + } + + // 扫描响应: 包含 Service UUID 以帮助发现 + uint8_t scan_rsp[31] = {0}; + int rsp_pos = 0; + scan_rsp[rsp_pos++] = 0x11; // 长度 (2 + 15) + scan_rsp[rsp_pos++] = 0x09; // 类型 = Complete Local Name + name_len = strlen(name); + if (name_len > (size_t)(31 - rsp_pos)) { + name_len = 31 - rsp_pos; + } + memcpy(&scan_rsp[rsp_pos], name, name_len); + rsp_pos += name_len; + + rc = ble_gap_adv_rsp_set_data(scan_rsp, rsp_pos); + if (rc != 0) { + DEBUG_WARN(TAG, "设置扫描响应数据失败: %d", rc); + } + + // 开始广播 + struct ble_gap_adv_params adv_params = {}; + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + // 从 kconfig 获取 BLE 地址类型,默认 Public +#ifdef CONFIG_BLE_ADDR_TYPE_PUBLIC + uint8_t own_addr_type = BLE_OWN_ADDR_PUBLIC; +#else + uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; +#endif + + rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, + &adv_params, ble_ota_gap_event, NULL); + if (rc != 0) { + DEBUG_ERR(TAG, "启动广播失败: %d", rc); + } else { + DEBUG_INFO(TAG, "BLE 广播已启动: \"%s\"", name); + } +} + +// ============================================================ +// NimBLE 同步/重置回调 +// ============================================================ + +static void ble_ota_on_sync(void) +{ + DEBUG_INFO(TAG, "NimBLE 协议栈同步完成"); + + // GATT 服务已在 ble_ota_server_start() 中注册,不再重复注册 + // 重复调用 ble_gatts_count_cfg / ble_gatts_add_svcs 会导致 BLE_HS_EBUSY + + s_ble_ready = true; + ble_ota_start_advertising(); +} + +static void ble_ota_on_reset(int reason) +{ + DEBUG_WARN(TAG, "NimBLE 协议栈重置: reason=%d", reason); + s_ble_ready = false; +} + +// ============================================================ +// NimBLE Host 任务(独立 FreeRTOS 任务) +// ============================================================ + +static void ble_ota_nimble_host_task(void *param) +{ + (void)param; + DEBUG_INFO(TAG, "NimBLE Host 任务启动"); + // nimble_port_run() 阻塞运行 NimBLE 事件循环 + nimble_port_run(); + // 正常情况下不会到达这里 + DEBUG_INFO(TAG, "NimBLE Host 任务退出"); +} + +// ============================================================ +// 公开 API +// ============================================================ + esp_err_t ble_ota_server_start(void) { - DEBUG_WARN("BLE", "BLE OTA 功能在 ESP-IDF 6.0 中暂时不可用"); - DEBUG_WARN("BLE", "请使用 WiFi OTA 功能或等待 BLE API 适配"); - return ESP_ERR_NOT_SUPPORTED; + int rc; + + DEBUG_INFO(TAG, "=== 初始化 BLE OTA GATT 服务器 ==="); + DEBUG_INFO(TAG, " Device: %s", BLE_DEVICE_NAME); + DEBUG_INFO(TAG, " MTU: %" PRIu16, BLE_MTU_SIZE); + DEBUG_INFO(TAG, " Svc: 0x%04X", BLE_OTA_SERVICE_UUID); + + // 1. 初始化 NimBLE 底层 + esp_err_t err = nimble_port_init(); + if (err != ESP_OK) { + DEBUG_ERR(TAG, "nimble_port_init 失败: %s", esp_err_to_name(err)); + return err; + } + DEBUG_INFO(TAG, "nimble_port_init 完成"); + + // 2. 初始化 GAP / GATT 服务(无需 BLE 存储回调 — 不做 bonding) + ble_svc_gap_init(); + ble_svc_gatt_init(); + + // 4. 设置设备名称 + rc = ble_svc_gap_device_name_set(BLE_DEVICE_NAME); + if (rc != 0) { + DEBUG_WARN(TAG, "设置设备名称失败: %d", rc); + } + + // 5. 配置 Host 回调 + // sync_cb: NimBLE 事件循环就绪时调用 (开始广播) + // reset_cb: NimBLE 重置时调用 + ble_hs_cfg.sync_cb = ble_ota_on_sync; + ble_hs_cfg.reset_cb = ble_ota_on_reset; + // 不做 bonding,不需要 store 回调 + + // 6. 预注册 GATT 服务(在 sync 回调中也会再注册一次确保) + rc = ble_gatts_count_cfg(gatt_ota_svcs); + if (rc != 0) { + DEBUG_ERR(TAG, "GATT 服务计数失败: %d", rc); + return ESP_FAIL; + } + + rc = ble_gatts_add_svcs(gatt_ota_svcs); + if (rc != 0) { + DEBUG_ERR(TAG, "GATT 服务注册失败: %d", rc); + return ESP_FAIL; + } + + // 7. 启动 NimBLE Host 任务(内部创建 FreeRTOS 任务跑 nimble_port_run) + nimble_port_freertos_init(ble_ota_nimble_host_task); + + DEBUG_INFO(TAG, "BLE OTA 服务器初始化完成"); + return ESP_OK; } -// 通过 BLE 通知 APP GD32 的响应 esp_err_t ble_ota_notify_response(const uint8_t *data, size_t len) { - (void)data; - (void)len; - return ESP_ERR_NOT_SUPPORTED; + if (!s_ble_connected) { + return ESP_ERR_NOT_SUPPORTED; + } + if (s_data_out_val_handle == 0) { + DEBUG_WARN(TAG, "DATA_OUT 值句柄未设置"); + return ESP_ERR_INVALID_STATE; + } + + if (len == 0) return ESP_OK; + + // 通过 NimBLE mbuf 发送通知 + struct os_mbuf *om = ble_hs_mbuf_from_flat(data, len); + if (om == NULL) { + DEBUG_ERR(TAG, "分配 mbuf 失败 (%zu 字节)", len); + return ESP_ERR_NO_MEM; + } + + int rc = ble_gattc_notify_custom(s_conn_handle, s_data_out_val_handle, om); + if (rc != 0) { + DEBUG_WARN(TAG, "通知发送失败: rc=%d", rc); + return ESP_FAIL; + } + + DEBUG_DBG(TAG, "通知已发送: %zu 字节", len); + return ESP_OK; } bool ble_ota_is_connected(void) @@ -101,31 +544,56 @@ bool ble_ota_is_connected(void) return s_ble_connected; } -// 信号通知 OTA 中继开始转发 void ble_ota_signal_relay(void) { - if (g_ota_dispatch_queue) { - uint32_t msg = 1; - BaseType_t ret = xQueueSend(g_ota_dispatch_queue, &msg, pdMS_TO_TICKS(100)); - if (ret == pdTRUE) { - DEBUG_INFO("BLE", "OTA 调度信号已通过 BLE 发送"); - } + if (g_ota_dispatch_queue == NULL) { + DEBUG_ERR(TAG, "OTA 调度队列未初始化"); + return; } + + uint32_t msg = 1; + BaseType_t ret = xQueueSend(g_ota_dispatch_queue, &msg, pdMS_TO_TICKS(200)); + if (ret != pdTRUE) { + DEBUG_ERR(TAG, "OTA 调度信号发送失败: 队列满"); + return; + } + + DEBUG_INFO(TAG, "OTA 调度信号已发送 → ota_relay_task"); } -// BLE OTA FreeRTOS 任务 +// ============================================================ +// BLE OTA FreeRTOS 任务入口 +// +// 注意: 此任务的职责是初始化 BLE 服务器并保持存活。 +// 实际的 BLE 事件循环在独立的 NimBLE Host 任务中运行。 +// 为避免与 ota_relay_task 竞争,此任务不从 g_ota_dispatch_queue 消费。 +// ============================================================ + void ble_ota_task(void *pvParameters) { (void)pvParameters; - DEBUG_WARN("BLE", "BLE OTA 任务启动,但功能暂时不可用"); - - // 等待调度信号 - while (1) { - uint32_t msg; - BaseType_t ret = xQueueReceive(g_ota_dispatch_queue, &msg, pdMS_TO_TICKS(1000)); - if (ret == pdTRUE) { - DEBUG_INFO("BLE", "收到 OTA 调度信号,但 BLE 功能不可用"); - } - vTaskDelay(pdMS_TO_TICKS(100)); + DEBUG_INFO(TAG, "=== BLE OTA 任务启动 ==="); + + // 初始化并启动 BLE 服务器(同步操作,完成后广播开始) + esp_err_t err = ble_ota_server_start(); + if (err != ESP_OK) { + DEBUG_ERR(TAG, "BLE 服务器启动失败: %s → BLE OTA 不可用", + esp_err_to_name(err)); } -} \ No newline at end of file + + // 保持任务存活 — 所有 BLE 事件由 NimBLE Host 任务处理 + uint32_t heartbeat = 0; + while (1) { + heartbeat++; + + // 每 60 秒打印一次心跳(确认任务存活) + if (heartbeat % 6 == 0) { + DEBUG_DBG(TAG, "心跳 #%lu | BLE %s | 连接: %s", + (unsigned long)(heartbeat / 6), + s_ble_ready ? "就绪" : "未就绪", + s_ble_connected ? "已连接" : "未连接"); + } + + vTaskDelay(pdMS_TO_TICKS(10000)); + } +} diff --git a/main/server/wifi_ota.cpp b/main/server/wifi_ota.cpp index 56639e4..6479c9e 100644 --- a/main/server/wifi_ota.cpp +++ b/main/server/wifi_ota.cpp @@ -10,11 +10,15 @@ #include "esp_netif.h" #include "esp_http_server.h" #include "esp_system.h" +#include "esp_chip_info.h" #include "esp_timer.h" +#include "esp_ota_ops.h" #include "nvs_flash.h" #include "lwip/netdb.h" #include "esp_netif.h" #include "esp_netif_types.h" +#include "esp_event.h" +#include "esp_mac.h" #include "app_config.h" #include "wifi_ota.h" @@ -25,12 +29,111 @@ #include "cJSON.h" static ota_wifi_mode_t s_wifi_mode = OTA_WIFI_MODE_AP; -static bool s_ota_storage_done = false; static bool s_relay_triggered = false; static bool s_sta_connected = false; +static int s_sta_retry_count = 0; +static SemaphoreHandle_t s_sta_connected_sem = NULL; +static SemaphoreHandle_t s_sta_got_ip_sem = NULL; + +// ESP32 OTA 状态 +static bool s_esp32_ota_active = false; +static esp_ota_handle_t s_esp32_ota_handle = 0; +static const esp_partition_t *s_esp32_update_partition = NULL; +static size_t s_esp32_received = 0; + +// GD32 OTA 存储状态 +static bool s_gd32_storage_done = false; static httpd_handle_t s_http_server = NULL; +static void wifi_set_static_ip(void); + +static void http_set_cors_headers(httpd_req_t *req) +{ + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_set_hdr(req, "Access-Control-Allow-Methods", "GET, POST, OPTIONS"); + httpd_resp_set_hdr(req, "Access-Control-Allow-Headers", "Content-Type"); + httpd_resp_set_hdr(req, "Access-Control-Max-Age", "600"); +} + +static esp_err_t http_options_handler(httpd_req_t *req) +{ + http_set_cors_headers(req); + httpd_resp_set_status(req, "204 No Content"); + httpd_resp_send(req, NULL, 0); + return ESP_OK; +} + +// ---------------------------------------- +// WiFi/IP 事件回调(事件驱动连接) +// ---------------------------------------- +static void wifi_event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT) { + switch (event_id) { + case WIFI_EVENT_STA_START: + DEBUG_INFO("WIFI", "STA 已启动,开始连接..."); + esp_wifi_connect(); + break; + + case WIFI_EVENT_STA_CONNECTED: + DEBUG_INFO("WIFI", "STA 已关联到 AP"); + s_sta_connected = true; + s_sta_retry_count = 0; + if (s_sta_connected_sem) { + xSemaphoreGive(s_sta_connected_sem); + } + break; + + case WIFI_EVENT_STA_DISCONNECTED: { + wifi_event_sta_disconnected_t* disconn = (wifi_event_sta_disconnected_t*)event_data; + DEBUG_WARN("WIFI", "STA 断开, reason=%d, retry=%d", disconn->reason, s_sta_retry_count); + s_sta_connected = false; + + if (s_sta_retry_count < WIFI_STA_MAX_RETRY) { + s_sta_retry_count++; + DEBUG_INFO("WIFI", "重连第 %d 次...", s_sta_retry_count); + esp_wifi_connect(); + } else { + DEBUG_ERR("WIFI", "STA 重连失败 %d 次,放弃", s_sta_retry_count); + } + break; + } + + case WIFI_EVENT_AP_STACONNECTED: { + wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*)event_data; + DEBUG_INFO("WIFI", "AP: 客户端 " MACSTR " 连入, AID=%d", MAC2STR(event->mac), event->aid); + break; + } + + case WIFI_EVENT_AP_STADISCONNECTED: { + wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*)event_data; + DEBUG_INFO("WIFI", "AP: 客户端 " MACSTR " 离开, AID=%d, reason=%d", + MAC2STR(event->mac), event->aid, event->reason); + break; + } + + default: + break; + } + } else if (event_base == IP_EVENT) { + switch (event_id) { + case IP_EVENT_STA_GOT_IP: { + ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data; + DEBUG_INFO("WIFI", "STA 获取 IP: " IPSTR, IP2STR(&event->ip_info.ip)); + if (s_sta_got_ip_sem) { + xSemaphoreGive(s_sta_got_ip_sem); + } + break; + } + + default: + break; + } + } +} + // ---------------------------------------- // WiFi AP 模式初始化 // ---------------------------------------- @@ -40,6 +143,29 @@ static esp_err_t wifi_init_ap(void) s_wifi_mode = OTA_WIFI_MODE_AP; + // 创建 AP netif 并设置自定义 IP + esp_netif_t *ap_netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"); + if (ap_netif == NULL) { + ap_netif = esp_netif_create_default_wifi_ap(); + } + if (ap_netif != NULL) { + // 停止 DHCP 服务器(必须先停才能改 IP) + esp_netif_dhcps_stop(ap_netif); + + esp_netif_ip_info_t ip_info; + memset(&ip_info, 0, sizeof(ip_info)); + // 方案 A:SoftAP 使用 192.168.31.0/24 网段 + // ESP32 自己作为 AP 网关,电脑连入后拿到 192.168.31.x + inet_pton(AF_INET, "192.168.31.1", &ip_info.ip); + inet_pton(AF_INET, "192.168.31.1", &ip_info.gw); + inet_pton(AF_INET, "255.255.255.0", &ip_info.netmask); + ESP_ERROR_CHECK(esp_netif_set_ip_info(ap_netif, &ip_info)); + + // 重新启动 DHCP 服务器,给连接的客户端分配 IP + esp_netif_dhcps_start(ap_netif); + DEBUG_INFO("WIFI", "AP IP 已设置: 192.168.31.1"); + } + wifi_config_t wifi_config = {}; memcpy(wifi_config.ap.ssid, WIFI_AP_SSID, strlen(WIFI_AP_SSID) + 1); wifi_config.ap.ssid_len = strlen(WIFI_AP_SSID); @@ -55,7 +181,8 @@ static esp_err_t wifi_init_ap(void) 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", "AP IP 地址: 192.168.31.1"); + DEBUG_INFO("WIFI", "AP 网关地址: 192.168.31.1"); DEBUG_INFO("WIFI", "最大连接数: %d", WIFI_AP_MAX_CONNECT); return ESP_OK; @@ -69,149 +196,410 @@ static esp_err_t wifi_init_sta(void) DEBUG_INFO("WIFI", "=== 初始化 WiFi STA 模式 ==="); s_wifi_mode = OTA_WIFI_MODE_STA; + s_sta_retry_count = 0; + + // ★ 设置国家代码:中国,允许信道 1-13 + // ESP32 默认国家是 US(只允许 1-11),中国路由可能用 12/13 + wifi_country_t country = {}; + memcpy(country.cc, "CN", 3); + country.schan = 1; + country.nchan = 13; + country.policy = WIFI_COUNTRY_POLICY_MANUAL; wifi_config_t wifi_config = {}; - wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK; + wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; + wifi_config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL; + wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; wifi_config.sta.pmf_cfg.capable = true; wifi_config.sta.pmf_cfg.required = false; + wifi_config.sta.listen_interval = 3; 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); + DEBUG_INFO("WIFI", "STA SSID: %s (全信道扫描, CN 国家代码)", WIFI_STA_SSID); + ESP_ERROR_CHECK(esp_wifi_set_country(&country)); 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()); - DEBUG_INFO("WIFI", "WiFi STA 连接中, SSID: %s...", WIFI_STA_SSID); + // 静态 IP 必须在 start/connect 之前配置,避免与 STA_START 自动连接发生竞态 + wifi_set_static_ip(); + + ESP_ERROR_CHECK(esp_wifi_start()); + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); + + DEBUG_INFO("WIFI", "WiFi STA 启动, SSID: %s, 事件驱动连接...", WIFI_STA_SSID); return ESP_OK; } -// 等待 STA 连接成功并获取 IP +// 等待 STA 连接成功并获取 IP(静态 IP 等 CONNECTED,DHCP 等 GOT_IP) static esp_err_t wifi_wait_sta_connected(char *ip_str, size_t len) { - int retry = 0; - while (retry < 60) { // 最多等 6 秒 - vTaskDelay(pdMS_TO_TICKS(100)); - wifi_ap_record_t ap_info; - if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) { - s_sta_connected = true; - esp_netif_ip_info_t ip_info; - esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); - if (netif != NULL && esp_netif_get_ip_info(netif, &ip_info) == ESP_OK) { - if (ip_str) { - snprintf(ip_str, len, IPSTR, IP2STR(&ip_info.ip)); - } - } - return ESP_OK; - } - retry++; + SemaphoreHandle_t wait_sem = WIFI_STA_USE_STATIC_IP ? s_sta_connected_sem : s_sta_got_ip_sem; + const char *wait_name = WIFI_STA_USE_STATIC_IP ? "STA_CONNECTED" : "STA_GOT_IP"; + + if (wait_sem == NULL) { + DEBUG_ERR("WIFI", "%s 信号量未创建", wait_name); + return ESP_ERR_INVALID_STATE; } + + TickType_t timeout_ticks = pdMS_TO_TICKS(WIFI_STA_CONNECT_TIMEOUT_MS); + if (xSemaphoreTake(wait_sem, timeout_ticks) == pdTRUE) { + esp_netif_ip_info_t ip_info; + esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (netif != NULL && esp_netif_get_ip_info(netif, &ip_info) == ESP_OK) { + if (ip_str) { + snprintf(ip_str, len, IPSTR, IP2STR(&ip_info.ip)); + } + DEBUG_INFO("WIFI", "%s 等待成功, 当前 IP: " IPSTR, wait_name, IP2STR(&ip_info.ip)); + } + s_sta_connected = true; + return ESP_OK; + } + + DEBUG_ERR("WIFI", "等待 %s 超时 (%d ms), 重连次数: %d", wait_name, WIFI_STA_CONNECT_TIMEOUT_MS, s_sta_retry_count); return ESP_ERR_TIMEOUT; } // 设置 STA 静态 IP static void wifi_set_static_ip(void) { -#if WIFI_STA_STATIC_IP_IS_ENABLED - esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); - if (sta_netif) { - ESP_ERROR_CHECK(esp_netif_dhcpc_stop(sta_netif)); + if (WIFI_STA_USE_STATIC_IP) { + esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (sta_netif) { + DEBUG_INFO("WIFI", "STA 使用静态 IP 模式,停止 DHCP Client"); + ESP_ERROR_CHECK(esp_netif_dhcpc_stop(sta_netif)); - esp_netif_ip_info_t info; - memset(&info, 0, sizeof(info)); - inet_pton(AF_INET, WIFI_STA_STATIC_IP, &info.ip); - inet_pton(AF_INET, WIFI_STA_STATIC_GW, &info.gw); - inet_pton(AF_INET, WIFI_STA_STATIC_NETMASK, &info.netmask); + esp_netif_ip_info_t info; + memset(&info, 0, sizeof(info)); + inet_pton(AF_INET, WIFI_STA_STATIC_IP, &info.ip); + inet_pton(AF_INET, WIFI_STA_STATIC_GW, &info.gw); + inet_pton(AF_INET, WIFI_STA_STATIC_NETMASK, &info.netmask); + ESP_ERROR_CHECK(esp_netif_set_ip_info(sta_netif, &info)); + DEBUG_INFO("WIFI", "静态 IP 已设置: %s", WIFI_STA_STATIC_IP); - ESP_ERROR_CHECK(esp_netif_set_ip_info(sta_netif, &info)); - DEBUG_INFO("WIFI", "静态 IP 已设置: %s", WIFI_STA_STATIC_IP); + // 设置 DNS + esp_netif_dns_info_t dns_info; + memset(&dns_info, 0, sizeof(dns_info)); + inet_pton(AF_INET, WIFI_STA_STATIC_DNS, &dns_info.ip.u_addr.ip4.addr); + ESP_ERROR_CHECK(esp_netif_set_dns_info(sta_netif, ESP_NETIF_DNS_MAIN, &dns_info)); + DEBUG_INFO("WIFI", "DNS 已设置: %s", WIFI_STA_STATIC_DNS); + } + } else { + DEBUG_INFO("WIFI", "使用 DHCP 获取 IP"); } -#else - DEBUG_INFO("WIFI", "使用 DHCP 获取 IP"); -#endif } // ---------------------------------------- -// HTTP POST /ota/upload 处理器 +// ESP32 OTA 内部函数 +// ---------------------------------------- +static esp_err_t esp32_ota_begin(size_t total_size) +{ + const esp_partition_t *boot_partition = esp_ota_get_running_partition(); + DEBUG_INFO("OTA", "当前启动分区: %s, size=%u, address=0x%lx", + boot_partition->label, boot_partition->size, boot_partition->address); + + s_esp32_update_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL); + if (s_esp32_update_partition == NULL || + s_esp32_update_partition->address == boot_partition->address) { + s_esp32_update_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL); + } + + if (s_esp32_update_partition == NULL) { + DEBUG_ERR("OTA", "找不到可用的 OTA 分区"); + return ESP_FAIL; + } + + DEBUG_INFO("OTA", "OTA 目标分区: %s, size=%u, address=0x%lx", + s_esp32_update_partition->label, + s_esp32_update_partition->size, + s_esp32_update_partition->address); + + if (total_size > s_esp32_update_partition->size) { + DEBUG_ERR("OTA", "固件太大: %u > 分区大小: %u", + total_size, s_esp32_update_partition->size); + return ESP_FAIL; + } + + esp_err_t err = esp_ota_begin(s_esp32_update_partition, total_size, &s_esp32_ota_handle); + if (err != ESP_OK) { + DEBUG_ERR("OTA", "esp_ota_begin 失败: %s", esp_err_to_name(err)); + s_esp32_update_partition = NULL; + return err; + } + + s_esp32_received = 0; + s_esp32_ota_active = true; + DEBUG_INFO("OTA", "ESP32 OTA 开始,目标分区: %s", s_esp32_update_partition->label); + return ESP_OK; +} + +static esp_err_t esp32_ota_write(const uint8_t *data, size_t len) +{ + if (!s_esp32_ota_active || s_esp32_update_partition == NULL) { + return ESP_ERR_INVALID_STATE; + } + esp_err_t err = esp_ota_write(s_esp32_ota_handle, data, len); + if (err == ESP_OK) { + s_esp32_received += len; + } + return err; +} + +// HTTP POST /ota/update - 完成 ESP32 OTA 并重启 +static esp_err_t esp32_ota_update_handler(httpd_req_t *req) +{ + (void)req; + http_set_cors_headers(req); + if (!s_esp32_ota_active) { + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "OTA not started"); + return ESP_FAIL; + } + + DEBUG_INFO("OTA", "ESP32 OTA 完成, 共 %u 字节, 设置启动分区...", s_esp32_received); + + esp_err_t err = esp_ota_end(s_esp32_ota_handle); + if (err != ESP_OK) { + DEBUG_ERR("OTA", "esp_ota_end 失败: %s", esp_err_to_name(err)); + s_esp32_ota_active = false; + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, esp_err_to_name(err)); + return ESP_FAIL; + } + + err = esp_ota_set_boot_partition(s_esp32_update_partition); + if (err != ESP_OK) { + DEBUG_ERR("OTA", "esp_ota_set_boot_partition 失败: %s", esp_err_to_name(err)); + s_esp32_ota_active = false; + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, esp_err_to_name(err)); + return ESP_FAIL; + } + + s_esp32_ota_active = false; + DEBUG_INFO("OTA", "ESP32 OTA 完成,重启中..."); + + const char resp[] = "{\"status\": \"ok\", \"message\": \"OTA finished, rebooting\"}"; + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + + vTaskDelay(pdMS_TO_TICKS(500)); + esp_restart(); + return ESP_OK; +} + +// HTTP GET /ota/update - 查询 ESP32 OTA 状态 +static esp_err_t esp32_ota_status_handler(httpd_req_t *req) +{ + http_set_cors_headers(req); + char resp[128]; + if (s_esp32_ota_active) { + snprintf(resp, sizeof(resp), + "{\"active\": true, \"received\": %u, \"partition\": \"%s\"}", + (unsigned int)s_esp32_received, + s_esp32_update_partition ? s_esp32_update_partition->label : "null"); + } else { + snprintf(resp, sizeof(resp), "{\"active\": false}"); + } + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + return ESP_OK; +} + +// 从 HTTP 流中读取完整的 JSON 头(以 } 结尾) +// 返回 JSON 字符串长度,失败返回 0 +static int recv_json_header(httpd_req_t *req, char *buf, int buf_size) +{ + int total = 0; + int depth = 1; // 开头的 '{' 已被 peek 消费,从 1 开始 + while (total < buf_size - 1) { + int ret = httpd_req_recv(req, buf + total, 1); // 逐字节读,精确找到 JSON 结尾 + if (ret <= 0) return 0; + total += ret; + buf[total] = '\0'; + if (buf[total - 1] == '{') depth++; + else if (buf[total - 1] == '}') { + depth--; + if (depth == 0) return total; // JSON 头读完 + } + } + return 0; // JSON 头太长,超出缓冲区 +} + +// ---------------------------------------- +// 统一 /ota/upload 处理器(自动识别目标) // ---------------------------------------- static esp_err_t ota_upload_handler(httpd_req_t *req) { + http_set_cors_headers(req); DEBUG_INFO("WIFI", "=== HTTP: POST /ota/upload ==="); DEBUG_INFO("WIFI", "收到固件上传请求, 内容长度: %d 字节", req->content_len); + // 预读 1 字节判断是 JSON 还是 binary + char peek; + int peek_ret = httpd_req_recv(req, &peek, 1); + if (peek_ret <= 0) { + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "接收失败"); + return ESP_FAIL; + } + + bool is_esp32_ota = false; + uint32_t total_size = 0; + int json_header_len = 0; + + if (peek == '{') { + // JSON 模式:逐字节读完 JSON 头 + char json_buf[256]; + json_buf[0] = peek; + json_header_len = recv_json_header(req, json_buf + 1, sizeof(json_buf) - 1); + if (json_header_len > 0) { + json_header_len++; // 加上已读的 peek 字节 + json_buf[json_header_len] = '\0'; + + cJSON *root = cJSON_Parse(json_buf); + if (root) { + cJSON *type_item = cJSON_GetObjectItem(root, "type"); + if (type_item && cJSON_IsString(type_item) && + strcmp(cJSON_GetStringValue(type_item), "esp32") == 0) { + is_esp32_ota = true; + DEBUG_INFO("WIFI", "检测到 ESP32 OTA, JSON 头长度: %d 字节", json_header_len); + } + cJSON *size_item = cJSON_GetObjectItem(root, "total_size"); + if (size_item) { + total_size = (uint32_t)cJSON_GetNumberValue(size_item); + } + cJSON_Delete(root); + } + } + } + + if (is_esp32_ota) { + // --- ESP32 OTA --- + if (total_size == 0) { + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "missing total_size"); + return ESP_FAIL; + } + + esp_err_t err = esp32_ota_begin(total_size); + if (err != ESP_OK) { + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "OTA begin failed"); + return ESP_FAIL; + } + + // 堆分配缓冲区,避免栈溢出(HTTP server 栈仅 8KB) + uint8_t *fw_buf = (uint8_t *)malloc(1024); + if (!fw_buf) { + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "内存分配失败"); + return ESP_FAIL; + } + + size_t total_firmware_written = 0; + size_t total_received = json_header_len; // 已消费的字节数 + int last_percent = 0; + + while (total_received < req->content_len) { + size_t to_read = req->content_len - total_received; + if (to_read > 1024) to_read = 1024; + + int ret = httpd_req_recv(req, (char *)fw_buf, to_read); + if (ret <= 0) break; + + err = esp32_ota_write(fw_buf, ret); + if (err != ESP_OK) { + DEBUG_ERR("WIFI", "OTA write 失败"); + break; + } + total_received += ret; + total_firmware_written += ret; + + if (total_size > 0) { + int percent = (int)((total_firmware_written * 100) / total_size); + if (percent / 10 > last_percent / 10) { + last_percent = percent; + DEBUG_INFO("WIFI", "ESP32 OTA 进度: %u / %u (%d%%)", + (unsigned int)total_firmware_written, total_size, percent); + } + } + } + + free(fw_buf); + DEBUG_INFO("WIFI", "ESP32 OTA 存储完成: %u 字节 (跳过 JSON 头 %d 字节)", (unsigned int)s_esp32_received, json_header_len); + const char resp[] = "{\"status\": \"ok\", \"message\": \"stored, call POST /ota/update to finish\", \"target\": \"esp32\"}"; + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, strlen(resp)); + return ESP_OK; + } + + // --- GD32 OTA(原逻辑)--- if (req->content_len > OTA_MAX_FIRMWARE_SIZE) { - DEBUG_ERR("WIFI", "固件太大: %d 字节 (最大 %d)", req->content_len, OTA_MAX_FIRMWARE_SIZE); + 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; } - uint8_t buf[OTA_BLOCK_SIZE]; + uint8_t *buf = (uint8_t *)malloc(OTA_BLOCK_SIZE); int received = 0; - int first_chunk = 1; - while (received < req->content_len) { - int remaining = req->content_len - received; - int to_read = remaining < sizeof(buf) ? remaining : sizeof(buf); + // peek 字节是 GD32 数据的第一字节,先放回缓冲区 + uint8_t gd32_header[6]; + gd32_header[0] = (uint8_t)peek; + int header_read = 1; + // 读剩余 5 字节凑齐 6 字节 GD32 头 + if (req->content_len >= 6) { + int need = 6 - header_read; + int got = httpd_req_recv(req, (char *)gd32_header + header_read, need); + if (got > 0) header_read += got; + } - int ret = httpd_req_recv(req, (char *)buf, to_read); - if (ret <= 0) { - DEBUG_ERR("WIFI", "HTTP 请求接收失败"); - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "接收失败"); - return ESP_FAIL; - } - - if (first_chunk && ret >= 6) { - uint16_t seq = buf[0] | (buf[1] << 8); - uint32_t total_size = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24); - - if (seq == 0) { - ota_meta_t meta = { - .total_size = total_size, - .stored_size = 0, - .last_seq = 0, - .chunk_count = (total_size + 4095) / 4096, - .checksum = {0} - }; - meta_save(&meta); - DEBUG_INFO("WIFI", "开始固件存储: %u 字节, %u 块", - total_size, meta.chunk_count); - } - first_chunk = 0; - } - - 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 写入失败, offset=%u, err=%d", flash_offset, err); - } - - meta_update(flash_offset + ret, received / OTA_BLOCK_SIZE); - - received += ret; - - // 每 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); + // 先处理已读的 header + if (header_read >= 6) { + uint16_t seq = gd32_header[0] | (gd32_header[1] << 8); + uint32_t fw_size = gd32_header[2] | (gd32_header[3] << 8) | (gd32_header[4] << 16) | (gd32_header[5] << 24); + if (seq == 0) { + ota_meta_t meta = { .total_size = fw_size, .stored_size = 0, .last_seq = 0, + .chunk_count = (fw_size + 4095) / 4096, .checksum = {0} }; + meta_save(&meta); + DEBUG_INFO("WIFI", "开始 GD32 固件存储: %u 字节", fw_size); } } - DEBUG_INFO("WIFI", "固件存储完成: %d 字节", received); + // 继续读剩余数据 + while (received + header_read < req->content_len) { + size_t to_read = req->content_len - received - header_read; + if (to_read > OTA_BLOCK_SIZE) to_read = OTA_BLOCK_SIZE; + + int ret = httpd_req_recv(req, (char *)buf, to_read); + if (ret <= 0) break; + + uint32_t flash_offset = ((received + header_read) / OTA_BLOCK_SIZE) * OTA_BLOCK_SIZE; + esp_err_t err = flash_write_chunk(flash_offset, buf, ret); + if (err == ESP_OK) { + meta_update(flash_offset + ret, (received + header_read) / OTA_BLOCK_SIZE); + } + received += ret; + + uint32_t progress = ((received + header_read) * 100) / req->content_len; + if (progress % 10 == 0) { + DEBUG_INFO("WIFI", "GD32 上传进度: %d / %d (%u%%)", + received + header_read, req->content_len, progress); + } + } + + free(buf); + DEBUG_INFO("WIFI", "GD32 固件存储完成: %d 字节", received + header_read); ota_meta_t meta; meta_load(&meta); if (meta.stored_size >= meta.total_size) { - s_ota_storage_done = true; - DEBUG_INFO("WIFI", "全部固件已存储,触发转发..."); + s_gd32_storage_done = true; + DEBUG_INFO("WIFI", "GD32 固件已存储,触发转发..."); wifi_ota_signal_relay(); } - const char resp[] = "{\"status\": \"ok\", \"progress\": 100}"; + const char resp[] = "{\"status\": \"ok\", \"progress\": 100, \"target\": \"gd32\"}"; httpd_resp_set_type(req, "application/json"); httpd_resp_send(req, resp, strlen(resp)); - return ESP_OK; } @@ -219,6 +607,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; + http_set_cors_headers(req); DEBUG_INFO("WIFI", "=== HTTP: POST /ota/relay ==="); DEBUG_INFO("WIFI", "收到触发 OTA 中继请求"); wifi_ota_signal_relay(); @@ -233,6 +622,7 @@ 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) { + http_set_cors_headers(req); DEBUG_INFO("WIFI", "=== HTTP: GET /ota/status ==="); ota_meta_t meta; @@ -244,12 +634,12 @@ static esp_err_t ota_status_handler(httpd_req_t *req) "\"storage_done\": %s, \"relay_state\": %d}", (unsigned long)meta.total_size, (unsigned long)meta.stored_size, (unsigned long)meta.last_seq, - s_ota_storage_done ? "true" : "false", + s_gd32_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"); + s_gd32_storage_done ? "true" : "false"); httpd_resp_set_type(req, "application/json"); httpd_resp_send(req, resp, len); @@ -260,6 +650,7 @@ static esp_err_t ota_status_handler(httpd_req_t *req) // HTTP GET /health 处理器 static esp_err_t health_handler(httpd_req_t *req) { + http_set_cors_headers(req); DEBUG_INFO("WIFI", "=== HTTP: GET /health ==="); health_state_t state = health_get_current(); @@ -278,12 +669,32 @@ static esp_err_t health_handler(httpd_req_t *req) return ESP_OK; } +// HTTP GET /logs - 拉取并清空日志缓冲区 +static esp_err_t logs_handler(httpd_req_t *req) +{ + http_set_cors_headers(req); + + int json_len = 0; + char *json = debug_log_ring_drain_json(&json_len); + + if (json && json_len > 0) { + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, json, json_len); + free(json); + } else { + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, "[]", 2); + } + return ESP_OK; +} + // HTTP POST /can/send 处理器 // 上位机发送 CAN 帧,经 ESP32 转发到 GD32 // 请求体: {"ch": 0, "id": 123456, "data": "0102030405060708", "dlc": 8} // data 为 hex 字符串(可不填,自动用 dlc 决定实际发送长度) static esp_err_t can_send_handler(httpd_req_t *req) { + http_set_cors_headers(req); char buf[256] = {0}; int ret = httpd_req_recv(req, buf, sizeof(buf) - 1); if (ret <= 0) { @@ -360,6 +771,7 @@ static esp_err_t can_send_handler(httpd_req_t *req) // HTTP GET /can/status 处理器 static esp_err_t can_status_handler(httpd_req_t *req) { + http_set_cors_headers(req); char resp[128]; snprintf(resp, sizeof(resp), "{\"channels\": 3, \"max_dlc\": %d, \"spi_init\": %s}", @@ -373,6 +785,7 @@ static esp_err_t can_status_handler(httpd_req_t *req) // HTTP GET /wifi/status 处理器 static esp_err_t wifi_status_handler(httpd_req_t *req) { + http_set_cors_headers(req); char resp[256]; char ip_str[16] = "0.0.0.0"; int8_t rssi = -127; @@ -401,6 +814,54 @@ static esp_err_t wifi_status_handler(httpd_req_t *req) return ESP_OK; } +// HTTP GET /system/status 处理器 +static esp_err_t system_status_handler(httpd_req_t *req) +{ + http_set_cors_headers(req); + + char ip_str[16] = "0.0.0.0"; + int8_t rssi = -127; + bool connected = false; + + if (s_wifi_mode == OTA_WIFI_MODE_STA && s_sta_connected) { + esp_netif_ip_info_t ip_info; + esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (sta_netif && esp_netif_get_ip_info(sta_netif, &ip_info) == ESP_OK) { + snprintf(ip_str, sizeof(ip_str), IPSTR, IP2STR(&ip_info.ip)); + } + wifi_ap_record_t ap_info; + if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) { + rssi = ap_info.rssi; + } + connected = true; + } + + ota_meta_t meta; + memset(&meta, 0, sizeof(meta)); + meta_load(&meta); + + char resp[640]; + int len = snprintf(resp, sizeof(resp), + "{\"version\": \"%s\", \"health\": %d, \"free_heap\": %lu, \"min_free_heap\": %lu, \"temperature\": %.1f, \"voltage\": %.2f, \"wifi\": {\"mode\": \"%s\", \"ip\": \"%s\", \"rssi\": %d, \"connected\": %s}, \"ota\": {\"total_size\": %lu, \"stored_size\": %lu, \"storage_done\": %s, \"relay_state\": %d}}", + FW_VERSION,health_get_current(), + (unsigned long)esp_get_free_heap_size(), + (unsigned long)esp_get_minimum_free_heap_size(), + (double)health_get_last_temperature(), + (double)health_get_last_voltage(), + s_wifi_mode == OTA_WIFI_MODE_AP ? "AP" : "STA", + ip_str, + rssi, + connected ? "true" : "false", + (unsigned long)meta.total_size, + (unsigned long)meta.stored_size, + s_gd32_storage_done ? "true" : "false", + g_relay_state); + + httpd_resp_set_type(req, "application/json"); + httpd_resp_send(req, resp, len); + return ESP_OK; +} + // ---------------------------------------- // 启动 HTTP OTA 服务器 // ---------------------------------------- @@ -409,6 +870,7 @@ static esp_err_t http_ota_server_start(void) httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.server_port = HTTP_SERVER_PORT; config.stack_size = HTTP_SERVER_STACK_SIZE; + config.max_uri_handlers = 32; // 现有业务端点 + 对应 OPTIONS 预检 DEBUG_INFO("WIFI", "=== 启动 HTTP OTA 服务器 ==="); DEBUG_INFO("WIFI", "HTTP 服务器端口: %d", config.server_port); @@ -426,6 +888,13 @@ static esp_err_t http_ota_server_start(void) .user_ctx = NULL }; httpd_register_uri_handler(s_http_server, &upload_uri); + httpd_uri_t upload_options_uri = { + .uri = "/ota/upload", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &upload_options_uri); httpd_uri_t relay_uri = { .uri = "/ota/relay", @@ -434,6 +903,13 @@ static esp_err_t http_ota_server_start(void) .user_ctx = NULL }; httpd_register_uri_handler(s_http_server, &relay_uri); + httpd_uri_t relay_options_uri = { + .uri = "/ota/relay", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &relay_options_uri); httpd_uri_t status_uri = { .uri = "/ota/status", @@ -442,6 +918,43 @@ static esp_err_t http_ota_server_start(void) .user_ctx = NULL }; httpd_register_uri_handler(s_http_server, &status_uri); + httpd_uri_t status_options_uri = { + .uri = "/ota/status", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &status_options_uri); + + httpd_uri_t esp32_update_uri = { + .uri = "/ota/update", + .method = HTTP_POST, + .handler = esp32_ota_update_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &esp32_update_uri); + httpd_uri_t esp32_update_options_uri = { + .uri = "/ota/update", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &esp32_update_options_uri); + + httpd_uri_t esp32_status_uri = { + .uri = "/ota/esp32_status", + .method = HTTP_GET, + .handler = esp32_ota_status_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &esp32_status_uri); + httpd_uri_t esp32_status_options_uri = { + .uri = "/ota/esp32_status", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &esp32_status_options_uri); httpd_uri_t health_uri = { .uri = "/health", @@ -450,6 +963,28 @@ static esp_err_t http_ota_server_start(void) .user_ctx = NULL }; httpd_register_uri_handler(s_http_server, &health_uri); + httpd_uri_t health_options_uri = { + .uri = "/health", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &health_options_uri); + + httpd_uri_t logs_uri = { + .uri = "/logs", + .method = HTTP_GET, + .handler = logs_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &logs_uri); + httpd_uri_t logs_options_uri = { + .uri = "/logs", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &logs_options_uri); httpd_uri_t wifi_status_uri = { .uri = "/wifi/status", @@ -458,6 +993,28 @@ static esp_err_t http_ota_server_start(void) .user_ctx = NULL }; httpd_register_uri_handler(s_http_server, &wifi_status_uri); + httpd_uri_t wifi_status_options_uri = { + .uri = "/wifi/status", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &wifi_status_options_uri); + + httpd_uri_t system_status_uri = { + .uri = "/system/status", + .method = HTTP_GET, + .handler = system_status_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &system_status_uri); + httpd_uri_t system_status_options_uri = { + .uri = "/system/status", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &system_status_options_uri); // CAN 帧转发 httpd_uri_t can_send_uri = { @@ -467,6 +1024,13 @@ static esp_err_t http_ota_server_start(void) .user_ctx = NULL }; httpd_register_uri_handler(s_http_server, &can_send_uri); + httpd_uri_t can_send_options_uri = { + .uri = "/can/send", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &can_send_options_uri); httpd_uri_t can_status_uri = { .uri = "/can/status", @@ -475,9 +1039,16 @@ static esp_err_t http_ota_server_start(void) .user_ctx = NULL }; httpd_register_uri_handler(s_http_server, &can_status_uri); + httpd_uri_t can_status_options_uri = { + .uri = "/can/status", + .method = HTTP_OPTIONS, + .handler = http_options_handler, + .user_ctx = NULL + }; + httpd_register_uri_handler(s_http_server, &can_status_options_uri); DEBUG_INFO("WIFI", "HTTP 服务器已启动"); - DEBUG_INFO("WIFI", "注册端点: /ota/upload, /ota/relay, /ota/status, /health, /wifi/status, /can/send, /can/status"); + DEBUG_INFO("WIFI", "注册端点: /ota/upload, /ota/relay, /ota/update, /ota/status, /ota/esp32_status, /health, /wifi/status, /system/status, /can/send, /can/status"); return ESP_OK; } @@ -523,8 +1094,81 @@ bool wifi_is_connected(void) return s_sta_connected; } +// ---------------------------------------- +// ★ WiFi 早期初始化(在 app_main 调度器启动前调用) +// 包括:NVS → netif → event handler → WiFi driver → 配置 → connect +// 返回:true = STA 模式已启动(正在连接),false = 需要切 AP +// ---------------------------------------- +bool wifi_early_init(void) +{ + DEBUG_INFO("WIFI", "=== WiFi 早期初始化 (调度器启动前) ==="); + + // NVS(WiFi 校准数据存储依赖 NVS) + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + // NVS 分区损坏或版本不匹配,擦除后重试 + DEBUG_WARN("WIFI", "NVS 分区异常 (%s),擦除后重试", esp_err_to_name(err)); + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + if (err != ESP_OK) { + DEBUG_ERR("WIFI", "NVS 初始化失败: %s", esp_err_to_name(err)); + } else { + DEBUG_INFO("WIFI", "NVS 初始化成功"); + } + + // 创建信号量 + s_sta_connected_sem = xSemaphoreCreateBinary(); + s_sta_got_ip_sem = xSemaphoreCreateBinary(); + if (!s_sta_connected_sem || !s_sta_got_ip_sem) { + DEBUG_ERR("WIFI", "创建信号量失败"); + } + + // 注册 WiFi/IP 事件回调(必须在 esp_wifi_init 之前) + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); + DEBUG_INFO("WIFI", "WiFi/IP 事件回调已注册"); + + // 创建 STA netif(必须在 esp_wifi_init 之前) + esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (sta_netif == NULL) { + sta_netif = esp_netif_create_default_wifi_sta(); + if (sta_netif == NULL) { + DEBUG_ERR("WIFI", "创建 STA netif 失败"); + } else { + DEBUG_INFO("WIFI", "STA netif 已创建"); + } + } else { + DEBUG_INFO("WIFI", "STA netif 已存在,跳过创建"); + } + + // WiFi driver 初始化(必须在 netif 创建之后) + wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&wifi_cfg)); + DEBUG_INFO("WIFI", "WiFi driver 初始化成功"); + + // STA 优先,失败时返回 false 让 task 切 AP + if (CONFIG_WIFI_MODE == 1) { + DEBUG_INFO("WIFI", "工作模式: STA (优先)"); + err = wifi_init_sta(); + if (err == ESP_OK) { + // 连接已触发(STA_START 事件驱动),返回 true + // 实际连接状态由 wifi_ota_task 等待确认 + return true; + } + DEBUG_WARN("WIFI", "STA 初始化失败,将切换 AP"); + return false; + } else { + DEBUG_INFO("WIFI", "工作模式: AP"); + wifi_init_ap(); + return false; // AP 模式,不需要等待连接 + } +} + // ---------------------------------------- // WiFi OTA FreeRTOS 任务 +// WiFi 初始化已在 app_main 中通过 wifi_early_init() 完成 +// 此任务负责:等待连接结果 → 启动 HTTP 服务器 → 状态监控 // ---------------------------------------- void wifi_ota_task(void *pvParameters) { @@ -532,65 +1176,73 @@ void wifi_ota_task(void *pvParameters) 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) { + // 等待 STA 连接结果(wifi_early_init 已触发连接) + if (wifi_get_mode() == OTA_WIFI_MODE_STA) { char ip_str[16] = {0}; - - // 设置静态 IP(如果配置了) - wifi_set_static_ip(); - - // 等待连接成功 - err = wifi_wait_sta_connected(ip_str, sizeof(ip_str)); + esp_err_t err = wifi_wait_sta_connected(ip_str, sizeof(ip_str)); if (err == ESP_OK) { DEBUG_INFO("WIFI", "STA 已连接, IP: %s", ip_str); } else { DEBUG_WARN("WIFI", "STA 连接超时,切换到 AP 模式..."); - esp_wifi_stop(); + esp_wifi_stop(); // 先停 STA,再切 AP s_wifi_mode = OTA_WIFI_MODE_AP; wifi_init_ap(); } } -#else - DEBUG_INFO("WIFI", "工作模式: AP"); - wifi_init_ap(); -#endif + // AP 模式:wifi_early_init 已完成,无需额外操作 // 启动 HTTP 服务器 - err = http_ota_server_start(); + esp_err_t err = http_ota_server_start(); if (err != ESP_OK) { DEBUG_ERR("WIFI", "HTTP 服务器启动失败"); } - DEBUG_INFO("WIFI", "=== WiFi OTA 服务器就绪 ==="); + // ★ WiFi 已连接,UDP 从这里开始能通 + // 等待网络栈稳定(ARP 表建立、路由就绪),避免首批 UDP 包丢失 + vTaskDelay(pdMS_TO_TICKS(500)); - // 定期检查 WiFi 状态 + // 启动摘要,发两遍确保上位机收到(第一包可能触发 ARP 被丢) + esp_chip_info_t chip; + esp_chip_info(&chip); + for (int i = 0; i < 2; i++) { + DEBUG_INFO("WIFI", "========================================"); + DEBUG_INFO("WIFI", "[启动摘要] ESP32-C3 OTA Relay v%s", FW_VERSION); + DEBUG_INFO("WIFI", "[启动摘要] Chip: %s, Rev %d", CONFIG_IDF_TARGET, chip.revision); + DEBUG_INFO("WIFI", "[启动摘要] Free heap: %lu bytes", (unsigned long)esp_get_free_heap_size()); + DEBUG_INFO("WIFI", "[启动摘要] WiFi: %s", wifi_get_mode() == OTA_WIFI_MODE_STA ? "STA" : "AP"); + DEBUG_INFO("WIFI", "[启动摘要] NVS + WiFi driver + netif + event handler 初始化完成"); + DEBUG_INFO("WIFI", "[启动摘要] HTTP 服务器端口: %d", HTTP_SERVER_PORT); + DEBUG_INFO("WIFI", "========================================"); + DEBUG_INFO("WIFI", "=== WiFi OTA 服务器就绪 ==="); + if (i == 0) vTaskDelay(pdMS_TO_TICKS(200)); + } + + // 心跳 + WiFi 状态监控 + // 每秒一次循环:每 3 秒发心跳包,每 10 秒检查 RSSI + uint32_t tick = 0; while (1) { - int8_t rssi = wifi_get_rssi(); - if (rssi != -127) { - health_update_from_wifi_rssi(rssi); + tick++; - if (rssi < WIFI_RSSI_CRITICAL) { - 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); + // 轻量心跳:每 3 秒发一次,上位机据此判断 ESP32 是否在线 + if (tick % 3 == 0 && s_sta_connected) { + const char hb[] = "{\"t\":\"hb\"}\n"; + debug_log_send((const uint8_t *)hb, sizeof(hb) - 1); + } + + // 每 10 秒检查一次 RSSI + if (tick % 10 == 0) { + int8_t rssi = wifi_get_rssi(); + if (rssi != -127) { + health_update_from_wifi_rssi(rssi); + + if (rssi < WIFI_RSSI_CRITICAL) { + 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); + } } } - vTaskDelay(pdMS_TO_TICKS(10000)); + vTaskDelay(pdMS_TO_TICKS(1000)); } } diff --git a/main/server/wifi_ota.h b/main/server/wifi_ota.h index 9df0f2d..490fc07 100644 --- a/main/server/wifi_ota.h +++ b/main/server/wifi_ota.h @@ -16,6 +16,11 @@ typedef enum { // WiFi OTA 任务入口 void wifi_ota_task(void *pvParameters); +// ★ WiFi 早期初始化(app_main 调度前调用) +// 包括 NVS、WiFi driver、netif、event handler、配置、连接尝试 +// 返回 true = STA 模式启动中,false = 需要在 task 中切换 AP +bool wifi_early_init(void); + // 信号通知 OTA 中继开始(存储完成后调用) void wifi_ota_signal_relay(void); diff --git a/main/softap_example_main.c b/main/softap_example_main.c deleted file mode 100644 index c2bca87..0000000 --- a/main/softap_example_main.c +++ /dev/null @@ -1,117 +0,0 @@ -/* WiFi softAP Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_mac.h" -#include "esp_wifi.h" -#include "esp_event.h" -#include "esp_log.h" -#include "nvs_flash.h" - -#include "lwip/err.h" -#include "lwip/sys.h" - -/* The examples use WiFi configuration that you can set via project configuration menu. - - If you'd rather not, just change the below entries to strings with - the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" -*/ -#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID -#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD -#define EXAMPLE_ESP_WIFI_CHANNEL CONFIG_ESP_WIFI_CHANNEL -#define EXAMPLE_MAX_STA_CONN CONFIG_ESP_MAX_STA_CONN - -#if CONFIG_ESP_GTK_REKEYING_ENABLE -#define EXAMPLE_GTK_REKEY_INTERVAL CONFIG_ESP_GTK_REKEY_INTERVAL -#else -#define EXAMPLE_GTK_REKEY_INTERVAL 0 -#endif - -static const char *TAG = "wifi softAP"; - -static void wifi_event_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) -{ - if (event_id == WIFI_EVENT_AP_STACONNECTED) { - wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data; - ESP_LOGI(TAG, "station "MACSTR" join, AID=%d", - MAC2STR(event->mac), event->aid); - } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { - wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; - ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d, reason=%d", - MAC2STR(event->mac), event->aid, event->reason); - } -} - -void wifi_init_softap(void) -{ - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - esp_netif_create_default_wifi_ap(); - - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - - ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, - ESP_EVENT_ANY_ID, - &wifi_event_handler, - NULL, - NULL)); - - wifi_config_t wifi_config = { - .ap = { - .ssid = EXAMPLE_ESP_WIFI_SSID, - .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID), - .channel = EXAMPLE_ESP_WIFI_CHANNEL, - .password = EXAMPLE_ESP_WIFI_PASS, - .max_connection = EXAMPLE_MAX_STA_CONN, -#ifdef CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT - .authmode = WIFI_AUTH_WPA3_PSK, - .sae_pwe_h2e = WPA3_SAE_PWE_BOTH, -#else /* CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT */ - .authmode = WIFI_AUTH_WPA2_PSK, -#endif - .pmf_cfg = { - .required = true, - }, -#ifdef CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT - .bss_max_idle_cfg = { - .period = WIFI_AP_DEFAULT_MAX_IDLE_PERIOD, - .protected_keep_alive = 1, - }, -#endif - .gtk_rekey_interval = EXAMPLE_GTK_REKEY_INTERVAL, - }, - }; - if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) { - wifi_config.ap.authmode = WIFI_AUTH_OPEN; - } - - 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()); - - ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d", - EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL); -} - -void app_main(void) -{ - //Initialize NVS - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - ESP_LOGI(TAG, "ESP_WIFI_MODE_AP"); - wifi_init_softap(); -} diff --git a/sdkconfig.bak.mbedtls_trim b/sdkconfig.bak.mbedtls_trim new file mode 100644 index 0000000..c3e91b9 --- /dev/null +++ b/sdkconfig.bak.mbedtls_trim @@ -0,0 +1,4032 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) 6.0.0 Project Configuration +# +# default: +CONFIG_SOC_ADC_SUPPORTED=y +# default: +CONFIG_SOC_DEDICATED_GPIO_SUPPORTED=y +# default: +CONFIG_SOC_UART_SUPPORTED=y +# default: +CONFIG_SOC_GDMA_SUPPORTED=y +# default: +CONFIG_SOC_UHCI_SUPPORTED=y +# default: +CONFIG_SOC_AHB_GDMA_SUPPORTED=y +# default: +CONFIG_SOC_GPTIMER_SUPPORTED=y +# default: +CONFIG_SOC_TWAI_SUPPORTED=y +# default: +CONFIG_SOC_BT_SUPPORTED=y +# default: +CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED=y +# default: +CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y +# default: +CONFIG_SOC_TEMP_SENSOR_SUPPORTED=y +# default: +CONFIG_SOC_XT_WDT_SUPPORTED=y +# default: +CONFIG_SOC_PHY_SUPPORTED=y +# default: +CONFIG_SOC_WIFI_SUPPORTED=y +# default: +CONFIG_SOC_SUPPORTS_SECURE_DL_MODE=y +# default: +CONFIG_SOC_EFUSE_KEY_PURPOSE_FIELD=y +# default: +CONFIG_SOC_EFUSE_HAS_EFUSE_RST_BUG=y +# default: +CONFIG_SOC_EFUSE_SUPPORTED=y +# default: +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +# default: +CONFIG_SOC_RTC_MEM_SUPPORTED=y +# default: +CONFIG_SOC_RTC_TIMER_V1_SUPPORTED=y +# default: +CONFIG_SOC_I2S_SUPPORTED=y +# default: +CONFIG_SOC_RMT_SUPPORTED=y +# default: +CONFIG_SOC_SDM_SUPPORTED=y +# default: +CONFIG_SOC_GPSPI_SUPPORTED=y +# default: +CONFIG_SOC_LEDC_SUPPORTED=y +# default: +CONFIG_SOC_I2C_SUPPORTED=y +# default: +CONFIG_SOC_SYSTIMER_SUPPORTED=y +# default: +CONFIG_SOC_SUPPORT_COEXISTENCE=y +# default: +CONFIG_SOC_AES_SUPPORTED=y +# default: +CONFIG_SOC_MPI_SUPPORTED=y +# default: +CONFIG_SOC_SHA_SUPPORTED=y +# default: +CONFIG_SOC_HMAC_SUPPORTED=y +# default: +CONFIG_SOC_DIG_SIGN_SUPPORTED=y +# default: +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +# default: +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +# default: +CONFIG_SOC_MEMPROT_SUPPORTED=y +# default: +CONFIG_SOC_BOD_SUPPORTED=y +# default: +CONFIG_SOC_CLK_TREE_SUPPORTED=y +# default: +CONFIG_SOC_ASSIST_DEBUG_SUPPORTED=y +# default: +CONFIG_SOC_WDT_SUPPORTED=y +# default: +CONFIG_SOC_SPI_FLASH_SUPPORTED=y +# default: +CONFIG_SOC_RNG_SUPPORTED=y +# default: +CONFIG_SOC_LIGHT_SLEEP_SUPPORTED=y +# default: +CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y +# default: +CONFIG_SOC_LP_PERIPH_SHARE_INTERRUPT=y +# default: +CONFIG_SOC_PM_SUPPORTED=y +# default: +CONFIG_SOC_XTAL_SUPPORT_40M=y +# default: +CONFIG_SOC_AES_SUPPORT_DMA=y +# default: +CONFIG_SOC_AES_GDMA=y +# default: +CONFIG_SOC_AES_SUPPORT_AES_128=y +# default: +CONFIG_SOC_AES_SUPPORT_AES_256=y +# default: +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +# default: +CONFIG_SOC_ADC_ARBITER_SUPPORTED=y +# default: +CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED=y +# default: +CONFIG_SOC_ADC_MONITOR_SUPPORTED=y +# default: +CONFIG_SOC_ADC_DMA_SUPPORTED=y +# default: +CONFIG_SOC_ADC_PERIPH_NUM=2 +# default: +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=5 +# default: +CONFIG_SOC_ADC_ATTEN_NUM=4 +# default: +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=1 +# default: +CONFIG_SOC_ADC_PATT_LEN_MAX=8 +# default: +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=12 +# default: +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +# default: +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=4 +# default: +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +# default: +CONFIG_SOC_ADC_DIGI_IIR_FILTER_NUM=2 +# default: +CONFIG_SOC_ADC_DIGI_MONITOR_NUM=2 +# default: +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=83333 +# default: +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=611 +# default: +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=12 +# default: +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +# default: +CONFIG_SOC_ADC_CALIBRATION_V1_SUPPORTED=y +# default: +CONFIG_SOC_ADC_SELF_HW_CALI_SUPPORTED=y +# default: +CONFIG_SOC_ADC_SHARED_POWER=y +# default: +CONFIG_SOC_APB_BACKUP_DMA=y +# default: +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED=y +# default: +CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y +# default: +CONFIG_SOC_CACHE_FREEZE_SUPPORTED=y +# default: +CONFIG_SOC_CACHE_MEMORY_IBANK_SIZE=0x4000 +# default: +CONFIG_SOC_CPU_CORES_NUM=1 +# default: +CONFIG_SOC_CPU_INTR_NUM=32 +# default: +CONFIG_SOC_CPU_HAS_FLEXIBLE_INTC=y +# default: +CONFIG_SOC_CPU_HAS_CSR_PC=y +# default: +CONFIG_SOC_CPU_BREAKPOINTS_NUM=8 +# default: +CONFIG_SOC_CPU_WATCHPOINTS_NUM=8 +# default: +CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=0x80000000 +# default: +CONFIG_SOC_DS_SIGNATURE_MAX_BIT_LEN=3072 +# default: +CONFIG_SOC_DS_KEY_PARAM_MD_IV_LENGTH=16 +# default: +CONFIG_SOC_DS_KEY_CHECK_MAX_WAIT_US=1100 +# default: +CONFIG_SOC_AHB_GDMA_VERSION=1 +# default: +CONFIG_SOC_GPIO_PORT=1 +# default: +CONFIG_SOC_GPIO_PIN_COUNT=22 +# default: +CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER=y +# default: +CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y +# default: +CONFIG_SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP=y +# default: +CONFIG_SOC_GPIO_IN_RANGE_MAX=21 +# default: +CONFIG_SOC_GPIO_OUT_RANGE_MAX=21 +# default: +CONFIG_SOC_GPIO_HP_PERIPH_PD_SLEEP_WAKEABLE_MASK=0 +# default: +CONFIG_SOC_GPIO_HP_PERIPH_PD_SLEEP_WAKEABLE_PIN_CNT=6 +# default: +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x00000000003FFFC0 +# default: +CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX=y +# default: +CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3 +# default: +CONFIG_SOC_I2C_NUM=1 +# default: +CONFIG_SOC_HP_I2C_NUM=1 +# default: +CONFIG_SOC_I2C_SUPPORT_XTAL=y +# default: +CONFIG_SOC_I2C_SUPPORT_RTC=y +# default: +CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y +# default: +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +# default: +CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST=y +# default: +CONFIG_SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE=y +# default: +CONFIG_SOC_I2S_HW_VERSION_2=y +# default: +CONFIG_SOC_I2S_SUPPORTS_PCM=y +# default: +CONFIG_SOC_I2S_SUPPORTS_PDM=y +# default: +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +# default: +CONFIG_SOC_I2S_SUPPORTS_PCM2PDM=y +# default: +CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y +# default: +CONFIG_SOC_I2S_PDM_MAX_TX_LINES=2 +# default: +CONFIG_SOC_I2S_PDM_MAX_RX_LINES=1 +# default: +CONFIG_SOC_I2S_SUPPORTS_TDM=y +# default: +CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y +# default: +CONFIG_SOC_LEDC_SUPPORT_XTAL_CLOCK=y +# default: +CONFIG_SOC_LEDC_TIMER_NUM=4 +# default: +CONFIG_SOC_LEDC_CHANNEL_NUM=6 +# default: +CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=14 +# default: +CONFIG_SOC_LEDC_SUPPORT_FADE_STOP=y +# default: +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=1 +# default: +CONFIG_SOC_MMU_PERIPH_NUM=1 +# default: +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +# default: +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +# default: +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=48 +# default: +CONFIG_SOC_RMT_SUPPORT_RX_PINGPONG=y +# default: +CONFIG_SOC_RMT_SUPPORT_TX_LOOP_COUNT=y +# default: +CONFIG_SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH=128 +# default: +CONFIG_SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM=108 +# default: +CONFIG_SOC_SLEEP_SYSTIMER_STALL_WORKAROUND=y +# default: +CONFIG_SOC_SLEEP_TGWDT_STOP_WORKAROUND=y +# default: +CONFIG_SOC_RTCIO_PIN_COUNT=0 +# default: +CONFIG_SOC_MPI_MEM_BLOCKS_NUM=4 +# default: +CONFIG_SOC_MPI_OPERATIONS_NUM=3 +# default: +CONFIG_SOC_RSA_MAX_BIT_LEN=3072 +# default: +CONFIG_SOC_SHA_DMA_MAX_BUFFER_SIZE=3968 +# default: +CONFIG_SOC_SHA_SUPPORT_DMA=y +# default: +CONFIG_SOC_SHA_SUPPORT_RESUME=y +# default: +CONFIG_SOC_SHA_GDMA=y +# default: +CONFIG_SOC_SHA_SUPPORT_SHA1=y +# default: +CONFIG_SOC_SHA_SUPPORT_SHA224=y +# default: +CONFIG_SOC_SHA_SUPPORT_SHA256=y +# default: +CONFIG_SOC_SPI_PERIPH_NUM=2 +# default: +CONFIG_SOC_SPI_MAX_CS_NUM=6 +# default: +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +# default: +CONFIG_SOC_SPI_SUPPORT_DDRCLK=y +# default: +CONFIG_SOC_SPI_SLAVE_SUPPORT_SEG_TRANS=y +# default: +CONFIG_SOC_SPI_SUPPORT_CD_SIG=y +# default: +CONFIG_SOC_SPI_SUPPORT_CONTINUOUS_TRANS=y +# default: +CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2=y +# default: +CONFIG_SOC_SPI_SUPPORT_CLK_APB=y +# default: +CONFIG_SOC_SPI_SUPPORT_CLK_XTAL=y +# default: +CONFIG_SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT=y +# default: +CONFIG_SOC_SPI_SCT_SUPPORTED=y +# default: +CONFIG_SOC_SPI_SCT_REG_NUM=14 +# default: +CONFIG_SOC_SPI_SCT_BUFFER_NUM_MAX=y +# default: +CONFIG_SOC_SPI_SCT_CONF_BITLEN_MAX=0x3FFFA +# default: +CONFIG_SOC_MEMSPI_IS_INDEPENDENT=y +# default: +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=16 +# default: +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE=y +# default: +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND=y +# default: +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_RESUME=y +# default: +CONFIG_SOC_SPI_MEM_SUPPORT_IDLE_INTR=y +# default: +CONFIG_SOC_SPI_MEM_SUPPORT_SW_SUSPEND=y +# default: +CONFIG_SOC_SPI_MEM_SUPPORT_CHECK_SUS=y +# default: +CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y +# default: +CONFIG_SOC_SPI_MEM_SUPPORT_WRAP=y +# default: +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +# default: +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +# default: +CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y +# default: +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +# default: +CONFIG_SOC_SYSTIMER_COUNTER_NUM=2 +# default: +CONFIG_SOC_SYSTIMER_ALARM_NUM=3 +# default: +CONFIG_SOC_SYSTIMER_BIT_WIDTH_LO=32 +# default: +CONFIG_SOC_SYSTIMER_BIT_WIDTH_HI=20 +# default: +CONFIG_SOC_SYSTIMER_FIXED_DIVIDER=y +# default: +CONFIG_SOC_SYSTIMER_INT_LEVEL=y +# default: +CONFIG_SOC_SYSTIMER_ALARM_MISS_COMPENSATE=y +# default: +CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32 +# default: +CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16 +# default: +CONFIG_SOC_MWDT_SUPPORT_XTAL=y +# default: +CONFIG_SOC_TWAI_CONTROLLER_NUM=1 +# default: +CONFIG_SOC_TWAI_MASK_FILTER_NUM=1 +# default: +CONFIG_SOC_EFUSE_DIS_DOWNLOAD_ICACHE=y +# default: +CONFIG_SOC_EFUSE_DIS_PAD_JTAG=y +# default: +CONFIG_SOC_EFUSE_DIS_USB_JTAG=y +# default: +CONFIG_SOC_EFUSE_DIS_DIRECT_BOOT=y +# default: +CONFIG_SOC_EFUSE_SOFT_DIS_JTAG=y +# default: +CONFIG_SOC_EFUSE_DIS_ICACHE=y +# default: +CONFIG_SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK=y +# default: +CONFIG_SOC_EFUSE_XTS_AES_KEY_128=y +# default: +CONFIG_SOC_SECURE_BOOT_V2_RSA=y +# default: +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=3 +# default: +CONFIG_SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS=y +# default: +CONFIG_SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY=y +# default: +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32 +# default: +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES=y +# default: +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128=y +# default: +CONFIG_SOC_MEMPROT_CPU_PREFETCH_PAD_SIZE=16 +# default: +CONFIG_SOC_MEMPROT_MEM_ALIGN_SIZE=512 +# default: +CONFIG_SOC_UART_NUM=2 +# default: +CONFIG_SOC_UART_HP_NUM=2 +# default: +CONFIG_SOC_UART_FIFO_LEN=128 +# default: +CONFIG_SOC_UART_BITRATE_MAX=5000000 +# default: +CONFIG_SOC_UART_SUPPORT_APB_CLK=y +# default: +CONFIG_SOC_UART_SUPPORT_RTC_CLK=y +# default: +CONFIG_SOC_UART_SUPPORT_XTAL_CLK=y +# default: +CONFIG_SOC_UART_SUPPORT_WAKEUP_INT=y +# default: +CONFIG_SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE=y +# default: +CONFIG_SOC_UHCI_NUM=1 +# default: +CONFIG_SOC_COEX_HW_PTI=y +# default: +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +# default: +CONFIG_SOC_MAC_BB_PD_MEM_SIZE=192 +# default: +CONFIG_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH=12 +# default: +CONFIG_SOC_PM_SUPPORT_WIFI_WAKEUP=y +# default: +CONFIG_SOC_PM_SUPPORT_BT_WAKEUP=y +# default: +CONFIG_SOC_PM_SUPPORT_CPU_PD=y +# default: +CONFIG_SOC_PM_SUPPORT_WIFI_PD=y +# default: +CONFIG_SOC_PM_SUPPORT_BT_PD=y +# default: +CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y +# default: +CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y +# default: +CONFIG_SOC_PM_SUPPORT_MAC_BB_PD=y +# default: +CONFIG_SOC_PM_CPU_RETENTION_BY_RTCCNTL=y +# default: +CONFIG_SOC_PM_MODEM_RETENTION_BY_BACKUPDMA=y +# default: +CONFIG_SOC_PM_MODEM_PD_BY_SW=y +# default: +CONFIG_SOC_CLK_RC_FAST_D256_SUPPORTED=y +# default: +CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y +# default: +CONFIG_SOC_CLK_RC_FAST_SUPPORT_CALIBRATION=y +# default: +CONFIG_SOC_CLK_XTAL32K_SUPPORTED=y +# default: +CONFIG_SOC_CLK_LP_FAST_SUPPORT_XTAL_D2=y +# default: +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC=y +# default: +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL=y +# default: +CONFIG_SOC_WIFI_HW_TSF=y +# default: +CONFIG_SOC_WIFI_FTM_SUPPORT=y +# default: +CONFIG_SOC_WIFI_GCMP_SUPPORT=y +# default: +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +# default: +CONFIG_SOC_WIFI_TXOP_SUPPORT=y +# default: +CONFIG_SOC_WIFI_CSI_SUPPORT=y +# default: +CONFIG_SOC_WIFI_MESH_SUPPORT=y +# default: +CONFIG_SOC_WIFI_SUPPORT_VARIABLE_BEACON_WINDOW=y +# default: +CONFIG_SOC_WIFI_PHY_NEEDS_USB_WORKAROUND=y +# default: +CONFIG_SOC_BLE_SUPPORTED=y +# default: +CONFIG_SOC_BLE_MESH_SUPPORTED=y +# default: +CONFIG_SOC_BLE_50_SUPPORTED=y +# default: +CONFIG_SOC_BLE_DEVICE_PRIVACY_SUPPORTED=y +# default: +CONFIG_SOC_BLUFI_SUPPORTED=y +# default: +CONFIG_SOC_PHY_COMBO_MODULE=y +# default: +CONFIG_IDF_CMAKE=y +# default: +CONFIG_IDF_TOOLCHAIN="gcc" +# default: +CONFIG_IDF_TOOLCHAIN_GCC=y +# default: +CONFIG_IDF_TARGET_ARCH_RISCV=y +# default: +CONFIG_IDF_TARGET_ARCH="riscv" +# default: +CONFIG_IDF_TARGET="esp32c3" +# default: +CONFIG_IDF_INIT_VERSION="6.0.0" +# default: +CONFIG_IDF_TARGET_ESP32C3=y +# default: +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0005 + +# +# Build type +# +# default: +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# default: +# CONFIG_APP_BUILD_TYPE_RAM is not set +# default: +CONFIG_APP_BUILD_GENERATE_BINARIES=y +# default: +CONFIG_APP_BUILD_BOOTLOADER=y +# default: +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# default: +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# default: +# CONFIG_APP_NO_BLOBS is not set +# end of Build type + +# +# Bootloader config +# + +# +# Bootloader manager +# +# default: +CONFIG_BOOTLOADER_COMPILE_TIME_DATE=y +# default: +CONFIG_BOOTLOADER_PROJECT_VER=1 +# end of Bootloader manager + +# +# Application Rollback +# +# default: +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# end of Application Rollback + +# +# Recovery Bootloader and Rollback +# +# end of Recovery Bootloader and Rollback + +# default: +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 +# default: +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# default: +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# default: +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set + +# +# Log +# +# default: +CONFIG_BOOTLOADER_LOG_VERSION_1=y +# default: +CONFIG_BOOTLOADER_LOG_VERSION=1 +# default: +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# default: +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# default: +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +# default: +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# default: +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# default: +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +# default: +CONFIG_BOOTLOADER_LOG_LEVEL=3 + +# +# Format +# +# default: +# CONFIG_BOOTLOADER_LOG_COLORS is not set +# default: +CONFIG_BOOTLOADER_LOG_TIMESTAMP_SOURCE_CPU_TICKS=y +# end of Format + +# +# Settings +# +# default: +CONFIG_BOOTLOADER_LOG_MODE_TEXT_EN=y +# default: +CONFIG_BOOTLOADER_LOG_MODE_TEXT=y +# end of Settings +# end of Log + +# default: +CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ=80 + +# +# Serial Flash Configurations +# +# default: +# CONFIG_BOOTLOADER_FLASH_DC_AWARE is not set +# default: +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Serial Flash Configurations + +# default: +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# default: +# CONFIG_BOOTLOADER_APP_TEST is not set +# default: +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +# default: +CONFIG_BOOTLOADER_WDT_ENABLE=y +# default: +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +# default: +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# default: +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# default: +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# default: +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +# default: +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# default: +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# +# default: +CONFIG_SECURE_BOOT_V2_RSA_SUPPORTED=y +# default: +CONFIG_SECURE_BOOT_V2_PREFERRED=y +# default: +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# default: +# CONFIG_SECURE_BOOT is not set +# default: +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# default: +CONFIG_SECURE_ROM_DL_MODE_ENABLED=y +# end of Security features + +# +# Application manager +# +# default: +CONFIG_APP_COMPILE_TIME_DATE=y +# default: +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# default: +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# default: +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +# default: +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=9 +# end of Application manager + +# default: +CONFIG_ESP_ROM_HAS_CRC_LE=y +# default: +CONFIG_ESP_ROM_HAS_CRC_BE=y +# default: +CONFIG_ESP_ROM_HAS_MZ_CRC32=y +# default: +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +# default: +CONFIG_ESP_ROM_UART_CLK_IS_XTAL=y +# default: +CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=3 +# default: +CONFIG_ESP_ROM_HAS_RETARGETABLE_LOCKING=y +# default: +CONFIG_ESP_ROM_HAS_ERASE_0_REGION_BUG=y +# default: +CONFIG_ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV=y +# default: +CONFIG_ESP_ROM_GET_CLK_FREQ=y +# default: +CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y +# default: +CONFIG_ESP_ROM_HAS_LAYOUT_TABLE=y +# default: +CONFIG_ESP_ROM_HAS_SPI_FLASH=y +# default: +CONFIG_ESP_ROM_HAS_SPI_FLASH_MMAP=y +# default: +CONFIG_ESP_ROM_HAS_ETS_PRINTF_BUG=y +# default: +CONFIG_ESP_ROM_HAS_NEWLIB=y +# default: +CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y +# default: +CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME=y +# default: +CONFIG_ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE=y +# default: +CONFIG_ESP_ROM_RAM_APP_NEEDS_MMU_INIT=y +# default: +CONFIG_ESP_ROM_HAS_SW_FLOAT=y +# default: +CONFIG_ESP_ROM_USB_OTG_NUM=-1 +# default: +CONFIG_ESP_ROM_HAS_VERSION=y +# default: +CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y +# default: +CONFIG_ESP_ROM_CONSOLE_OUTPUT_SECONDARY=y +# default: +CONFIG_ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY=y + +# +# Boot ROM Behavior +# +# default: +CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y +# default: +# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set +# default: +# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set +# default: +# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set +# end of Boot ROM Behavior + +# +# Serial flasher config +# +# default: +# CONFIG_ESPTOOLPY_NO_STUB is not set +# default: +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# default: +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +# default: +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# default: +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +# default: +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +# default: +CONFIG_ESPTOOLPY_FLASHMODE="dio" +# default: +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# default: +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# default: +# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set +# default: +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +# default: +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +# default: +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +# default: +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +# default: +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# default: +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +# default: +CONFIG_ESPTOOLPY_BEFORE="default-reset" +# default: +CONFIG_ESPTOOLPY_AFTER_RESET=y +# default: +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +# default: +CONFIG_ESPTOOLPY_AFTER="hard-reset" +# default: +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="config/partitions.csv" +# default: +CONFIG_PARTITION_TABLE_FILENAME="config/partitions.csv" +# default: +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +# default: +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# ESP32_COMM Configuration +# +# default: +CONFIG_ESP_WIFI_SSID="ESP32_OTA_RELAY" +# default: +CONFIG_ESP_WIFI_PASSWORD="12345678" +# default: +CONFIG_ESP_WIFI_CHANNEL=6 +# default: +CONFIG_ESP_MAX_STA_CONN=4 +# end of ESP32_COMM Configuration + +# +# Compiler options +# +# default: +CONFIG_COMPILER_OPTIMIZATION_DEBUG=y +# default: +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# default: +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# default: +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +# default: +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# default: +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# default: +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +# default: +# CONFIG_COMPILER_ASSERT_NDEBUG_EVALUATE is not set +# default: +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y +# default: +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# default: +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +# default: +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# default: +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# default: +# CONFIG_COMPILER_CXX_RTTI is not set +# default: +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# default: +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# default: +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# default: +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# default: +# CONFIG_COMPILER_NO_MERGE_CONSTANTS is not set +# default: +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# default: +# CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS is not set +# default: +# CONFIG_COMPILER_DISABLE_DEFAULT_ERRORS is not set +# default: +# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set +# default: +# CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set +# default: +# CONFIG_COMPILER_DISABLE_GCC14_WARNINGS is not set +# default: +# CONFIG_COMPILER_DISABLE_GCC15_WARNINGS is not set +# default: +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# default: +CONFIG_COMPILER_RT_LIB_GCCLIB=y +# default: +CONFIG_COMPILER_RT_LIB_NAME="gcc" +# default: +CONFIG_COMPILER_ORPHAN_SECTIONS_ERROR=y +# default: +# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set +# default: +# CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE is not set +# default: +# CONFIG_COMPILER_STATIC_ANALYZER is not set +# default: +CONFIG_COMPILER_CXX_GLIBCXX_CONSTEXPR_NO_CHANGE=y +# default: +# CONFIG_COMPILER_CXX_GLIBCXX_CONSTEXPR_COLD_CONSTEXPR is not set +# default: +# CONFIG_COMPILER_CXX_GLIBCXX_CONSTEXPR_COLD is not set +# end of Compiler options + +# +# Component config +# + +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +# CONFIG_BT_BLUEDROID_ENABLED is not set +CONFIG_BT_NIMBLE_ENABLED=y +# CONFIG_BT_CONTROLLER_ONLY is not set +# default: +CONFIG_BT_CONTROLLER_ENABLED=y +# default: +# CONFIG_BT_CONTROLLER_DISABLED is not set + +# +# NimBLE Options +# + +# +# General +# +# default: +CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y +# default: +# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set +# default: +CONFIG_BT_NIMBLE_PINNED_TO_CORE=0 +CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=4096 +# default: +CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE=y +# end of General + +# +# Roles and Profiles +# +# CONFIG_BT_NIMBLE_ROLE_CENTRAL is not set +CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y +CONFIG_BT_NIMBLE_ROLE_BROADCASTER=y +# CONFIG_BT_NIMBLE_ROLE_OBSERVER is not set +# default: +CONFIG_BT_NIMBLE_GATT_SERVER=y +# end of Roles and Profiles + +# +# Security (SMP) +# +# CONFIG_BT_NIMBLE_SECURITY_ENABLE is not set +# end of Security (SMP) + +# +# GAP +# +# default: +CONFIG_BT_NIMBLE_RPA_TIMEOUT=900 +CONFIG_BT_NIMBLE_WHITELIST_SIZE=12 +# default: +CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=y +# default: +CONFIG_BT_NIMBLE_MAX_CONN_REATTEMPT=3 +# default: +CONFIG_BT_NIMBLE_HS_PVCY=y +# default: +# CONFIG_BT_NIMBLE_HOST_ALLOW_CONNECT_WITH_SCAN is not set +# default: +# CONFIG_BT_NIMBLE_HOST_QUEUE_CONG_CHECK is not set +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=3 +CONFIG_BT_NIMBLE_MAX_CCCDS=8 +CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=y +CONFIG_BT_NIMBLE_HS_STOP_TIMEOUT_MS=2000 +CONFIG_BT_NIMBLE_USE_ESP_TIMER=y +# default: +# CONFIG_BT_NIMBLE_HS_FLOW_CTRL is not set +# end of GAP + +# +# GATT / ATT +# +# default: +CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=256 +# default: +CONFIG_BT_NIMBLE_ATT_MAX_PREP_ENTRIES=64 +# default: +CONFIG_BT_NIMBLE_GATT_MAX_PROCS=4 +# default: +# CONFIG_BT_NIMBLE_BLE_GATT_BLOB_TRANSFER is not set +# default: +# CONFIG_BT_NIMBLE_GATT_CACHING is not set +# default: +# CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY is not set +# end of GATT / ATT + +# +# L2CAP +# +CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM=0 +# end of L2CAP + +# +# Memory Settings +# +# default: +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=12 +# default: +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_SIZE=256 +# default: +CONFIG_BT_NIMBLE_MSYS_2_BLOCK_COUNT=24 +# default: +CONFIG_BT_NIMBLE_MSYS_2_BLOCK_SIZE=320 +# default: +CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=24 +# default: +CONFIG_BT_NIMBLE_TRANSPORT_ACL_SIZE=255 +# default: +CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70 +# default: +CONFIG_BT_NIMBLE_TRANSPORT_EVT_COUNT=30 +# default: +CONFIG_BT_NIMBLE_TRANSPORT_EVT_DISCARD_COUNT=8 +# default: +CONFIG_BT_NIMBLE_L2CAP_COC_SDU_BUFF_COUNT=1 +# default: +# CONFIG_BT_NIMBLE_MEMPOOL_RUNTIME_ALLOC is not set +# end of Memory Settings + +# +# BLE 5.x Features +# +# default: +CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y +# default: +CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_2M_PHY=y +# default: +CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_CODED_PHY=y +# default: +# CONFIG_BT_NIMBLE_EXT_ADV is not set +# default: +# CONFIG_BT_NIMBLE_EXT_SCAN is not set +# default: +# CONFIG_BT_NIMBLE_ISO is not set +# end of BLE 5.x Features + +# +# Services +# +# default: +CONFIG_BT_NIMBLE_PROX_SERVICE=y +# default: +CONFIG_BT_NIMBLE_ANS_SERVICE=y +# default: +CONFIG_BT_NIMBLE_CTS_SERVICE=y +# default: +CONFIG_BT_NIMBLE_HTP_SERVICE=y +# default: +CONFIG_BT_NIMBLE_IPSS_SERVICE=y +# default: +CONFIG_BT_NIMBLE_TPS_SERVICE=y +# default: +CONFIG_BT_NIMBLE_IAS_SERVICE=y +# default: +CONFIG_BT_NIMBLE_LLS_SERVICE=y +# default: +CONFIG_BT_NIMBLE_SPS_SERVICE=y +# default: +CONFIG_BT_NIMBLE_HR_SERVICE=y +# default: +# CONFIG_BT_NIMBLE_HID_SERVICE is not set +# default: +CONFIG_BT_NIMBLE_BAS_SERVICE=y +# default: +# CONFIG_BT_NIMBLE_SVC_BAS_BATTERY_LEVEL_NOTIFY is not set +# default: +CONFIG_BT_NIMBLE_DIS_SERVICE=y +# default: +# CONFIG_BT_NIMBLE_SVC_DIS_MANUFACTURER_NAME is not set +# default: +# CONFIG_BT_NIMBLE_SVC_DIS_SERIAL_NUMBER is not set +# default: +# CONFIG_BT_NIMBLE_SVC_DIS_HARDWARE_REVISION is not set +# default: +# CONFIG_BT_NIMBLE_SVC_DIS_FIRMWARE_REVISION is not set +# default: +# CONFIG_BT_NIMBLE_SVC_DIS_SOFTWARE_REVISION is not set +# default: +# CONFIG_BT_NIMBLE_SVC_DIS_SYSTEM_ID is not set +# default: +# CONFIG_BT_NIMBLE_SVC_DIS_PNP_ID is not set +# default: +# CONFIG_BT_NIMBLE_SVC_DIS_INCLUDED is not set +# default: +CONFIG_BT_NIMBLE_GAP_SERVICE=y +# default: +CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="nimble" +# default: +CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_ENC=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_AUTHEN=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_AUTHOR=0 +# default: +# CONFIG_BT_NIMBLE_SVC_GAP_GATT_SECURITY_LEVEL is not set +# default: +# CONFIG_BT_NIMBLE_SVC_GAP_RPA_ONLY is not set +# default: +CONFIG_BT_NIMBLE_SVC_GAP_CAR_CHAR_NOT_SUPP=y +# default: +# CONFIG_BT_NIMBLE_SVC_GAP_CAR_NOT_SUPP is not set +# default: +# CONFIG_BT_NIMBLE_SVC_GAP_CAR_SUPP is not set +# default: +CONFIG_BT_NIMBLE_SVC_GAP_CENT_ADDR_RESOLUTION=-1 + +# +# GAP Appearance write permissions +# +# default: +# CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE is not set +# default: +CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ENC=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ATHN=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ATHR=0 +# end of GAP Appearance write permissions + +# +# GAP device name write permissions +# +# default: +# CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE is not set +# end of GAP device name write permissions + +# +# Peripheral Preferred Connection Parameters (PPCP) settings +# +# default: +CONFIG_BT_NIMBLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SLAVE_LATENCY=0 +# default: +CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SUPERVISION_TMO=0 +# end of Peripheral Preferred Connection Parameters (PPCP) settings +# end of Services + +# +# Extra Features +# +# default: +# CONFIG_BT_NIMBLE_DYNAMIC_SERVICE is not set +# CONFIG_BT_NIMBLE_BLUFI_ENABLE is not set +# default: +# CONFIG_BT_NIMBLE_ENC_ADV_DATA is not set +# default: +# CONFIG_BT_NIMBLE_ADV_UUID_CONCAT is not set +# default: +# CONFIG_BT_NIMBLE_GATTC_PROC_PREEMPTION_PROTECT is not set +# default: +# CONFIG_BT_NIMBLE_GATTC_AUTO_PAIR is not set +# default: +CONFIG_BT_NIMBLE_EATT_CHAN_NUM=0 +# default: +# CONFIG_BT_NIMBLE_SUBRATE is not set +# default: +CONFIG_BT_NIMBLE_DTM_MODE_TEST=y +# default: +CONFIG_BT_NIMBLE_MEM_OPTIMIZATION=y +# default: +CONFIG_BT_NIMBLE_STATIC_TO_DYNAMIC=y +# default: +CONFIG_BT_NIMBLE_SM_SIGN_CNT=y +# default: +CONFIG_BT_NIMBLE_CPFD_CAFD=y +# default: +CONFIG_BT_NIMBLE_RECONFIG_MTU=y +# default: +# CONFIG_BT_NIMBLE_LOW_SPEED_MODE is not set +# end of Extra Features + +# +# NimBLE Mesh +# +# CONFIG_BT_NIMBLE_MESH is not set +# end of NimBLE Mesh + +# +# Host-controller Transport +# +# default: +CONFIG_UART_HW_FLOWCTRL_DISABLE=y +# default: +# CONFIG_UART_HW_FLOWCTRL_CTS_RTS is not set +# default: +CONFIG_BT_NIMBLE_HCI_UART_FLOW_CTRL=0 +# default: +CONFIG_BT_NIMBLE_HCI_UART_RTS_PIN=19 +# default: +CONFIG_BT_NIMBLE_HCI_UART_CTS_PIN=23 +# end of Host-controller Transport + +# +# Debugging/Testing +# +# default: +# CONFIG_BT_NIMBLE_MEM_DEBUG is not set +# default: +# CONFIG_BT_NIMBLE_LOG_LEVEL_NONE is not set +# default: +# CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR is not set +# default: +# CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING is not set +# default: +CONFIG_BT_NIMBLE_LOG_LEVEL_INFO=y +# default: +# CONFIG_BT_NIMBLE_LOG_LEVEL_DEBUG is not set +# default: +CONFIG_BT_NIMBLE_LOG_LEVEL=1 +# default: +CONFIG_BT_NIMBLE_PRINT_ERR_NAME=y +# default: +# CONFIG_BT_NIMBLE_DEBUG is not set +# CONFIG_BT_NIMBLE_TEST_THROUGHPUT_TEST is not set +# end of Debugging/Testing + +# +# Vendor / Optimization +# +# default: +# CONFIG_BT_NIMBLE_VS_SUPPORT is not set +# default: +# CONFIG_BT_NIMBLE_HIGH_DUTY_ADV_ITVL is not set +# end of Vendor / Optimization + +# +# Helper Utils +# +# default: +CONFIG_BT_NIMBLE_CHK_HOST_STATUS=y +# default: +CONFIG_BT_NIMBLE_UTIL_API=y +# default: +CONFIG_BT_NIMBLE_EXTRA_ADV_FIELDS=y +# end of Helper Utils +# end of NimBLE Options + +# +# Controller Options +# +# default: +CONFIG_BT_CTRL_MODE_EFF=1 +CONFIG_BT_CTRL_BLE_MAX_ACT=10 +# default: +CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=10 +CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0 +# default: +CONFIG_BT_CTRL_PINNED_TO_CORE=0 +# default: +CONFIG_BT_CTRL_HCI_MODE_VHCI=y +# default: +# CONFIG_BT_CTRL_HCI_MODE_UART_H4 is not set +# default: +CONFIG_BT_CTRL_HCI_TL=1 +# default: +CONFIG_BT_CTRL_ADV_DUP_FILT_MAX=30 +# default: +CONFIG_BT_BLE_CCA_MODE_NONE=y +# default: +# CONFIG_BT_BLE_CCA_MODE_HW is not set +# default: +# CONFIG_BT_BLE_CCA_MODE_SW is not set +# default: +CONFIG_BT_BLE_CCA_MODE=0 +# default: +CONFIG_BT_CTRL_HW_CCA_VAL=75 +# default: +CONFIG_BT_CTRL_HW_CCA_EFF=0 +# default: +CONFIG_BT_CTRL_CE_LENGTH_TYPE_ORIG=y +# default: +# CONFIG_BT_CTRL_CE_LENGTH_TYPE_CE is not set +# default: +# CONFIG_BT_CTRL_CE_LENGTH_TYPE_SD is not set +# default: +CONFIG_BT_CTRL_CE_LENGTH_TYPE_EFF=0 +# default: +CONFIG_BT_CTRL_TX_ANTENNA_INDEX_0=y +# default: +# CONFIG_BT_CTRL_TX_ANTENNA_INDEX_1 is not set +# default: +CONFIG_BT_CTRL_TX_ANTENNA_INDEX_EFF=0 +# default: +CONFIG_BT_CTRL_RX_ANTENNA_INDEX_0=y +# default: +# CONFIG_BT_CTRL_RX_ANTENNA_INDEX_1 is not set +# default: +CONFIG_BT_CTRL_RX_ANTENNA_INDEX_EFF=0 +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N24 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N21 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N18 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N15 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N12 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N9 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N6 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N3 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N0 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P3 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P6 is not set +# default: +CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P9=y +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P12 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P15 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P18 is not set +# default: +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P20 is not set +# default: +CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_EFF=11 +# default: +CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y +# default: +CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM=100 +# default: +CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20 +# default: +CONFIG_BT_CTRL_BLE_SCAN_DUPL=y +# default: +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DEVICE=y +# default: +# CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA is not set +# default: +# CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE is not set +# default: +CONFIG_BT_CTRL_SCAN_DUPL_TYPE=0 +# default: +CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE=100 +# default: +CONFIG_BT_CTRL_DUPL_SCAN_CACHE_REFRESH_PERIOD=0 +# default: +# CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN is not set +# default: +# CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EN is not set +# default: +CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_DIS=y +# default: +CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF=0 + +# +# MODEM SLEEP Options +# +# default: +# CONFIG_BT_CTRL_MODEM_SLEEP is not set +# end of MODEM SLEEP Options + +# default: +CONFIG_BT_CTRL_SLEEP_MODE_EFF=0 +# default: +CONFIG_BT_CTRL_SLEEP_CLOCK_EFF=0 +# default: +CONFIG_BT_CTRL_HCI_TL_EFF=1 +# default: +# CONFIG_BT_CTRL_AGC_RECORRECT_EN is not set +# default: +# CONFIG_BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX is not set +# default: +# CONFIG_BT_BLE_ADV_DATA_LENGTH_ZERO_AUX is not set +# default: +CONFIG_BT_CTRL_CHAN_ASS_EN=y +# default: +CONFIG_BT_CTRL_LE_PING_EN=y + +# +# BLE disconnects when Instant Passed (0x28) occurs +# +# default: +# CONFIG_BT_CTRL_BLE_LLCP_CONN_UPDATE is not set +# default: +# CONFIG_BT_CTRL_BLE_LLCP_CHAN_MAP_UPDATE is not set +# default: +# CONFIG_BT_CTRL_BLE_LLCP_PHY_UPDATE is not set +# end of BLE disconnects when Instant Passed (0x28) occurs + +# default: +# CONFIG_BT_CTRL_RUN_IN_FLASH_ONLY is not set +# default: +CONFIG_BT_CTRL_DTM_ENABLE=y +# default: +CONFIG_BT_CTRL_BLE_MASTER=y +# default: +# CONFIG_BT_CTRL_BLE_TEST is not set +# default: +CONFIG_BT_CTRL_BLE_SCAN=y +# default: +CONFIG_BT_CTRL_BLE_SECURITY_ENABLE=y +# default: +CONFIG_BT_CTRL_BLE_ADV=y +# default: +# CONFIG_BT_CTRL_CHECK_CONNECT_IND_ACCESS_ADDRESS is not set + +# +# Controller debug log Options (Experimental) +# +# end of Controller debug log Options (Experimental) +# end of Controller Options + +# +# Common Options +# +# default: +CONFIG_BT_ALARM_MAX_NUM=50 + +# +# BLE Log +# +# default: +# CONFIG_BLE_LOG_ENABLED is not set +# end of BLE Log + +# default: +# CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED is not set +# default: +# CONFIG_BT_BLE_LOG_UHCI_OUT_ENABLED is not set +# default: +# CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED is not set +# end of Common Options + +# default: +# CONFIG_BT_HCI_LOG_DEBUG_EN is not set +# end of Bluetooth + +# default: +# CONFIG_BLE_MESH is not set + +# +# Console Library +# +# default: +# CONFIG_CONSOLE_SORTED_HELP is not set +# end of Console Library + +# +# Legacy Driver Configurations +# + +# +# Legacy TWAI Driver Configurations +# +# default: +# CONFIG_TWAI_ISR_IN_IRAM_LEGACY is not set +# default: +# CONFIG_TWAI_SUPPRESS_DEPRECATE_WARN is not set +# default: +# CONFIG_TWAI_SKIP_LEGACY_CONFLICT_CHECK is not set +# end of Legacy TWAI Driver Configurations + +# +# Legacy I2C Driver Configurations +# +# default: +# CONFIG_I2C_SUPPRESS_DEPRECATE_WARN is not set +# default: +# CONFIG_I2C_SKIP_LEGACY_CONFLICT_CHECK is not set +# end of Legacy I2C Driver Configurations +# end of Legacy Driver Configurations + +# +# eFuse Bit Manager +# +# default: +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# default: +# CONFIG_EFUSE_VIRTUAL is not set +# default: +CONFIG_EFUSE_MAX_BLK_LEN=256 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +# default: +CONFIG_ESP_TLS_USING_MBEDTLS=y +# default: +# CONFIG_ESP_TLS_CUSTOM_STACK is not set +# default: +# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set +# default: +CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y +# default: +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# default: +# CONFIG_ESP_TLS_SERVER_SESSION_TICKETS is not set +# default: +# CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK is not set +# default: +# CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL is not set +# default: +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# default: +# CONFIG_ESP_TLS_INSECURE is not set +# default: +CONFIG_ESP_TLS_DYN_BUF_STRATEGY_SUPPORTED=y +# end of ESP-TLS + +# +# ADC and ADC Calibration +# +# default: +# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set +# default: +# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set +# default: +# CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3 is not set +# default: +# CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3 is not set +# default: +# CONFIG_ADC_ENABLE_DEBUG_LOG is not set +# end of ADC and ADC Calibration + +# +# Wireless Coexistence +# +# default: +CONFIG_ESP_COEX_ENABLED=y +# default: +CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y +# default: +# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set +# default: +# CONFIG_ESP_COEX_GPIO_DEBUG is not set +# end of Wireless Coexistence + +# +# Common ESP-related +# +# default: +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# GDMA Configurations +# +# default: +CONFIG_GDMA_CTRL_FUNC_IN_IRAM=y +# default: +CONFIG_GDMA_ISR_HANDLER_IN_IRAM=y +# default: +CONFIG_GDMA_OBJ_DRAM_SAFE=y +# default: +# CONFIG_GDMA_ENABLE_DEBUG_LOG is not set +# end of GDMA Configurations + +# +# ESP-Driver:GPIO Configurations +# +# default: +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:GPIO Configurations + +# +# ESP-Driver:GPTimer Configurations +# +# default: +CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y +# default: +# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set +# default: +# CONFIG_GPTIMER_ISR_CACHE_SAFE is not set +# default: +CONFIG_GPTIMER_OBJ_CACHE_SAFE=y +# default: +# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:GPTimer Configurations + +# +# ESP-Driver:I2C Configurations +# +# default: +# CONFIG_I2C_ISR_IRAM_SAFE is not set +# default: +# CONFIG_I2C_ENABLE_DEBUG_LOG is not set +# default: +CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM=y +# end of ESP-Driver:I2C Configurations + +# +# ESP-Driver:I2S Configurations +# +# default: +# CONFIG_I2S_ISR_IRAM_SAFE is not set +# default: +# CONFIG_I2S_CTRL_FUNC_IN_IRAM is not set +# default: +# CONFIG_I2S_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:I2S Configurations + +# +# ESP-Driver:I3C Master Configurations +# +# default: +# CONFIG_I3C_MASTER_ISR_CACHE_SAFE is not set +# default: +# CONFIG_I3C_MASTER_ENABLE_DEBUG_LOG is not set +# default: +# CONFIG_I3C_MASTER_ISR_HANDLER_IN_IRAM is not set +# end of ESP-Driver:I3C Master Configurations + +# +# ESP-Driver:LEDC Configurations +# +# default: +# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:LEDC Configurations + +# +# ESP-Driver:RMT Configurations +# +# default: +CONFIG_RMT_ENCODER_FUNC_IN_IRAM=y +# default: +CONFIG_RMT_TX_ISR_HANDLER_IN_IRAM=y +# default: +CONFIG_RMT_RX_ISR_HANDLER_IN_IRAM=y +# default: +# CONFIG_RMT_RECV_FUNC_IN_IRAM is not set +# default: +# CONFIG_RMT_TX_ISR_CACHE_SAFE is not set +# default: +# CONFIG_RMT_RX_ISR_CACHE_SAFE is not set +# default: +CONFIG_RMT_OBJ_CACHE_SAFE=y +# default: +# CONFIG_RMT_ENABLE_DEBUG_LOG is not set +# default: +# CONFIG_RMT_ISR_IRAM_SAFE is not set +# end of ESP-Driver:RMT Configurations + +# +# ESP-Driver:Sigma Delta Modulator Configurations +# +# default: +# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set +# default: +# CONFIG_SDM_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:Sigma Delta Modulator Configurations + +# +# ESP-Driver:SPI Configurations +# +# default: +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# default: +# CONFIG_SPI_SLAVE_IN_IRAM is not set +# default: +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of ESP-Driver:SPI Configurations + +# +# ESP-Driver:Temperature Sensor Configurations +# +# default: +# CONFIG_TEMP_SENSOR_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:Temperature Sensor Configurations + +# +# ESP-Driver:TWAI Configurations +# +# default: +# CONFIG_TWAI_ISR_IN_IRAM is not set +# default: +# CONFIG_TWAI_IO_FUNC_IN_IRAM is not set +# default: +# CONFIG_TWAI_ISR_CACHE_SAFE is not set +# default: +# CONFIG_TWAI_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:TWAI Configurations + +# +# ESP-Driver:UART Configurations +# +# default: +# CONFIG_UART_ISR_IN_IRAM is not set +# end of ESP-Driver:UART Configurations + +# +# ESP-Driver:UHCI Configurations +# +# default: +# CONFIG_UHCI_ISR_HANDLER_IN_IRAM is not set +# default: +# CONFIG_UHCI_ISR_CACHE_SAFE is not set +# default: +# CONFIG_UHCI_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:UHCI Configurations + +# +# ESP-Driver:USB Serial/JTAG Configuration +# +# default: +CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y +# end of ESP-Driver:USB Serial/JTAG Configuration + +# +# Ethernet +# +# default: +CONFIG_ETH_ENABLED=y +# default: +CONFIG_ETH_USE_SPI_ETHERNET=y +# default: +# CONFIG_ETH_USE_OPENETH is not set +# default: +# CONFIG_ETH_TRANSMIT_MUTEX is not set +# end of Ethernet + +# +# Event Loop Library +# +# default: +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +# default: +CONFIG_ESP_EVENT_POST_FROM_ISR=y +# default: +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# default: +CONFIG_ESP_GDBSTUB_ENABLED=y +# default: +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set +# default: +CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y +# default: +CONFIG_ESP_GDBSTUB_MAX_TASKS=32 +# end of GDB Stub + +# +# ESP HID +# +# default: +CONFIG_ESPHID_TASK_SIZE_BT=2048 +# default: +CONFIG_ESPHID_TASK_SIZE_BLE=4096 +# end of ESP HID + +# +# ESP HTTP client +# +# default: +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# default: +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +# default: +# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set +# default: +# CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT is not set +# default: +# CONFIG_ESP_HTTP_CLIENT_ENABLE_GET_CONTENT_RANGE is not set +# default: +CONFIG_ESP_HTTP_CLIENT_EVENT_POST_TIMEOUT=2000 +# end of ESP HTTP client + +# +# HTTP Server +# +# default: +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 +# default: +CONFIG_HTTPD_MAX_URI_LEN=512 +# default: +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +# default: +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# default: +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# default: +# CONFIG_HTTPD_WS_SUPPORT is not set +# default: +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +# default: +CONFIG_HTTPD_SERVER_EVENT_POST_TIMEOUT=2000 +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# default: +# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set +# default: +# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set +# default: +CONFIG_ESP_HTTPS_OTA_EVENT_POST_TIMEOUT=2000 +# default: +# CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# default: +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# default: +CONFIG_ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT=2000 +# default: +# CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# +# default: +CONFIG_ESP_HW_SUPPORT_FUNC_IN_IRAM=y + +# +# Chip revision +# +# default: +# CONFIG_ESP32C3_REV_MIN_0 is not set +# default: +# CONFIG_ESP32C3_REV_MIN_1 is not set +# default: +# CONFIG_ESP32C3_REV_MIN_2 is not set +# default: +CONFIG_ESP32C3_REV_MIN_3=y +# default: +# CONFIG_ESP32C3_REV_MIN_4 is not set +# default: +# CONFIG_ESP32C3_REV_MIN_101 is not set +# default: +CONFIG_ESP32C3_REV_MIN_FULL=3 +# default: +CONFIG_ESP_REV_MIN_FULL=3 + +# +# Maximum Supported ESP32-C3 Revision (Rev v1.99) +# +# default: +CONFIG_ESP32C3_REV_MAX_FULL=199 +# default: +CONFIG_ESP_REV_MAX_FULL=199 +# default: +CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL=0 +# default: +CONFIG_ESP_EFUSE_BLOCK_REV_MAX_FULL=199 + +# +# Maximum Supported ESP32-C3 eFuse Block Revision (eFuse Block Rev v1.99) +# +# end of Chip revision + +# +# MAC Config +# +# default: +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +# default: +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +# default: +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +# default: +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +# default: +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y +# default: +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4 +# default: +# CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO is not set +# default: +CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_FOUR=y +# default: +CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES=4 +# default: +# CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC is not set +# end of MAC Config + +# +# Sleep Config +# +# default: +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set +# default: +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +# default: +# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set +# default: +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y +# default: +CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=0 +# default: +# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set +# default: +# CONFIG_ESP_SLEEP_DEBUG is not set +# default: +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +# default: +CONFIG_RTC_CLK_SRC_INT_RC=y +# default: +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# default: +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# default: +# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set +# default: +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# default: +CONFIG_RTC_CLK_FUNC_IN_IRAM=y +# default: +CONFIG_RTC_TIME_FUNC_IN_IRAM=y +# end of RTC Clock Config + +# +# Peripheral Control +# +# default: +CONFIG_ESP_PERIPH_CTRL_FUNC_IN_IRAM=y +# default: +CONFIG_ESP_REGI2C_CTRL_FUNC_IN_IRAM=y +# end of Peripheral Control + +# +# Main XTAL Config +# +# default: +CONFIG_XTAL_FREQ_40=y +# default: +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config + +# +# Power Supplier +# + +# +# Brownout Detector +# +# default: +CONFIG_ESP_BROWNOUT_DET=y +# default: +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y +# default: +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# default: +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# default: +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# default: +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# default: +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +# default: +CONFIG_ESP_BROWNOUT_DET_LVL=7 +# default: +CONFIG_ESP_BROWNOUT_USE_INTR=y +# end of Brownout Detector +# end of Power Supplier + +# default: +CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM=y +# default: +CONFIG_ESP_INTR_IN_IRAM=y +# end of Hardware Settings + +# +# ESP-Driver:LCD Controller Configurations +# +# default: +# CONFIG_LCD_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:LCD Controller Configurations + +# +# LibC +# +# default: +# CONFIG_LIBC_NEWLIB is not set +# default: +CONFIG_LIBC_PICOLIBC=y +# default: +CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY=y +# default: +CONFIG_LIBC_MISC_IN_IRAM=y +# default: +CONFIG_LIBC_LOCKS_PLACE_IN_IRAM=y +# default: +CONFIG_LIBC_STDOUT_LINE_ENDING_CRLF=y +# default: +# CONFIG_LIBC_STDOUT_LINE_ENDING_LF is not set +# default: +# CONFIG_LIBC_STDOUT_LINE_ENDING_CR is not set +# default: +# CONFIG_LIBC_STDIN_LINE_ENDING_CRLF is not set +# default: +# CONFIG_LIBC_STDIN_LINE_ENDING_LF is not set +# default: +CONFIG_LIBC_STDIN_LINE_ENDING_CR=y +# default: +CONFIG_LIBC_TIME_SYSCALL_USE_RTC_HRT=y +# default: +# CONFIG_LIBC_TIME_SYSCALL_USE_RTC is not set +# default: +# CONFIG_LIBC_TIME_SYSCALL_USE_HRT is not set +# default: +# CONFIG_LIBC_TIME_SYSCALL_USE_NONE is not set +# default: +CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS=y +# default: +CONFIG_LIBC_ASSERT_BUFFER_SIZE=200 +# end of LibC + +# +# ESP-MM: Memory Management Configurations +# +# end of ESP-MM: Memory Management Configurations + +# +# ESP NETIF Adapter +# +# default: +CONFIG_ESP_NETIF_LOST_IP_TIMER_ENABLE=y +# default: +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +# default: +# CONFIG_ESP_NETIF_PROVIDE_CUSTOM_IMPLEMENTATION is not set +# default: +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# default: +# CONFIG_ESP_NETIF_LOOPBACK is not set +# default: +CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y +# default: +CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC=y +# default: +CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS=y +# default: +# CONFIG_ESP_NETIF_L2_TAP is not set +# default: +# CONFIG_ESP_NETIF_BRIDGE_EN is not set +# default: +# CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF is not set +# end of ESP NETIF Adapter + +# +# Partition API Configuration +# +# end of Partition API Configuration + +# +# PHY +# +# default: +CONFIG_ESP_PHY_ENABLED=y +# default: +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# default: +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +# default: +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +# default: +CONFIG_ESP_PHY_MAX_TX_POWER=20 +# default: +# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set +# default: +CONFIG_ESP_PHY_ENABLE_USB=y +# default: +# CONFIG_ESP_PHY_ENABLE_CERT_TEST is not set +# default: +CONFIG_ESP_PHY_RF_CAL_PARTIAL=y +# default: +# CONFIG_ESP_PHY_RF_CAL_NONE is not set +# default: +# CONFIG_ESP_PHY_RF_CAL_FULL is not set +# default: +CONFIG_ESP_PHY_CALIBRATION_MODE=0 +# default: +CONFIG_ESP_PHY_PLL_TRACK_PERIOD_MS=1000 +# default: +# CONFIG_ESP_PHY_PLL_TRACK_DEBUG is not set +# default: +# CONFIG_ESP_PHY_RECORD_USED_TIME is not set +# default: +CONFIG_ESP_PHY_IRAM_OPT=y +# default: +# CONFIG_ESP_PHY_DEBUG is not set +# end of PHY + +# +# Power Management +# +# default: +# CONFIG_PM_SLEEP_FUNC_IN_IRAM is not set +# default: +# CONFIG_PM_ENABLE is not set +# default: +# CONFIG_PM_SLP_IRAM_OPT is not set +# default: +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y +# default: +CONFIG_PM_ESP_SLEEP_POWER_DOWN_CPU=y +# end of Power Management + +# +# ESP PSRAM +# + +# +# ESP Ringbuf +# +# default: +# CONFIG_RINGBUF_IN_IRAM is not set +# default: +# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP-ROM +# +# default: +CONFIG_ESP_ROM_PRINT_IN_IRAM=y +# end of ESP-ROM + +# +# ESP Security Specific +# +# end of ESP Security Specific + +# +# ESP-STDIO +# +# default: +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# default: +# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# default: +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# default: +# CONFIG_ESP_CONSOLE_NONE is not set +# default: +# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set +# default: +CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +# default: +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y +# default: +CONFIG_ESP_CONSOLE_UART=y +# default: +CONFIG_ESP_CONSOLE_UART_NUM=0 +# default: +CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0 +# default: +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +# end of ESP-STDIO + +# +# ESP System Settings +# +# default: +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +# default: +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y +# default: +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 +# default: +CONFIG_ESP_SYSTEM_IN_IRAM=y +# default: +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +# default: +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# default: +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# default: +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +# default: +CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0 +# default: +CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y +# default: +CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y +# default: +CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y +# default: +CONFIG_ESP_SYSTEM_NO_BACKTRACE=y +# default: +# CONFIG_ESP_SYSTEM_USE_EH_FRAME is not set +# default: +# CONFIG_ESP_SYSTEM_USE_FRAME_POINTER is not set +# default: +CONFIG_ESP_SYSTEM_MEMPROT=y +# default: +CONFIG_ESP_SYSTEM_MEMPROT_PMS=y +# default: +CONFIG_ESP_SYSTEM_MEMPROT_PMS_LOCK=y +# default: +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +# default: +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +# default: +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +# default: +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# default: +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +# default: +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +# default: +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +# default: +CONFIG_ESP_INT_WDT=y +# default: +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +# default: +CONFIG_ESP_TASK_WDT_EN=y +# default: +CONFIG_ESP_TASK_WDT_INIT=y +# default: +# CONFIG_ESP_TASK_WDT_PANIC is not set +# default: +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +# default: +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +# default: +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# default: +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +# default: +CONFIG_ESP_DEBUG_OCDAWARE=y +# default: +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y +# default: +CONFIG_ESP_SYSTEM_HW_STACK_GUARD=y +# default: +CONFIG_ESP_SYSTEM_HW_PC_RECORD=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +# default: +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +# end of IPC (Inter-Processor Call) + +# +# ESP Timer (High Resolution Timer) +# +# default: +CONFIG_ESP_TIMER_IN_IRAM=y +# default: +# CONFIG_ESP_TIMER_PROFILING is not set +# default: +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +# default: +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +# default: +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +# default: +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# default: +# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set +# default: +CONFIG_ESP_TIMER_TASK_AFFINITY=0x0 +# default: +CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y +# default: +CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y +# default: +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +# default: +CONFIG_ESP_TIMER_IMPL_SYSTIMER=y +# end of ESP Timer (High Resolution Timer) + +# +# ESP Trace Configuration +# +# default: +# CONFIG_ESP_TRACE_LIB_EXTERNAL is not set +# default: +CONFIG_ESP_TRACE_LIB_NONE=y +# default: +CONFIG_ESP_TRACE_LIB_NAME="none" +# default: +# CONFIG_ESP_TRACE_TRANSPORT_APPTRACE is not set +# default: +CONFIG_ESP_TRACE_TRANSPORT_NONE=y +# default: +CONFIG_ESP_TRACE_TRANSPORT_NAME="none" +# end of ESP Trace Configuration + +# +# Wi-Fi +# +# default: +CONFIG_ESP_WIFI_ENABLED=y +# default: +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10 +# default: +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# default: +# CONFIG_ESP_WIFI_STATIC_TX_BUFFER is not set +# default: +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER=y +# default: +CONFIG_ESP_WIFI_TX_BUFFER_TYPE=1 +# default: +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +# default: +CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y +# default: +# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set +# default: +CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0 +# default: +CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5 +# default: +# CONFIG_ESP_WIFI_CSI_ENABLED is not set +# default: +CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y +# default: +CONFIG_ESP_WIFI_TX_BA_WIN=6 +# default: +CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y +# default: +CONFIG_ESP_WIFI_RX_BA_WIN=6 +# default: +CONFIG_ESP_WIFI_NVS_ENABLED=y +# default: +CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752 +# default: +CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32 +# default: +CONFIG_ESP_WIFI_IRAM_OPT=y +# default: +# CONFIG_ESP_WIFI_EXTRA_IRAM_OPT is not set +# default: +CONFIG_ESP_WIFI_RX_IRAM_OPT=y +# default: +CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y +# default: +CONFIG_ESP_WIFI_ENABLE_SAE_H2E=y +# default: +CONFIG_ESP_WIFI_ENABLE_SAE_PK=y +# default: +CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y +# default: +CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y +# default: +CONFIG_ESP_WIFI_WPA3_COMPATIBLE_SUPPORT=y +# default: +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +# default: +CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME=50 +# default: +# CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT is not set +# default: +CONFIG_ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME=10 +# default: +CONFIG_ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME=15 +# default: +# CONFIG_ESP_WIFI_FTM_ENABLE is not set +# default: +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y +# default: +# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set +# default: +CONFIG_ESP_WIFI_GMAC_SUPPORT=y +# default: +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# default: +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +# default: +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +# default: +CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y +# default: +CONFIG_ESP_WIFI_MBEDTLS_TLS_CLIENT=y +# default: +# CONFIG_ESP_WIFI_WAPI_PSK is not set +# default: +# CONFIG_ESP_WIFI_SUITE_B_192 is not set +# default: +# CONFIG_ESP_WIFI_11KV_SUPPORT is not set +# default: +# CONFIG_ESP_WIFI_MBO_SUPPORT is not set +# default: +# CONFIG_ESP_WIFI_DPP_SUPPORT is not set +# default: +# CONFIG_ESP_WIFI_11R_SUPPORT is not set +# default: +# CONFIG_ESP_WIFI_WPS_SOFTAP_REGISTRAR is not set + +# +# WPS Configuration Options +# +# default: +# CONFIG_ESP_WIFI_WPS_STRICT is not set +# default: +# CONFIG_ESP_WIFI_WPS_PASSPHRASE is not set +# default: +# CONFIG_ESP_WIFI_WPS_RECONNECT_ON_FAIL is not set +# end of WPS Configuration Options + +# default: +# CONFIG_ESP_WIFI_DEBUG_PRINT is not set +# default: +CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT=y +# default: +# CONFIG_ESP_WIFI_ENT_FREE_DYNAMIC_BUFFER is not set +# end of Wi-Fi + +# +# Core dump +# +# default: +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# default: +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +# default: +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +# default: +CONFIG_FATFS_VOLUME_COUNT=2 +# default: +# CONFIG_FATFS_LFN_NONE is not set +# default: +CONFIG_FATFS_LFN_HEAP=y +# default: +# CONFIG_FATFS_LFN_STACK is not set +# default: +# CONFIG_FATFS_SECTOR_512 is not set +# default: +CONFIG_FATFS_SECTOR_4096=y +# default: +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +# default: +CONFIG_FATFS_CODEPAGE_437=y +# default: +# CONFIG_FATFS_CODEPAGE_720 is not set +# default: +# CONFIG_FATFS_CODEPAGE_737 is not set +# default: +# CONFIG_FATFS_CODEPAGE_771 is not set +# default: +# CONFIG_FATFS_CODEPAGE_775 is not set +# default: +# CONFIG_FATFS_CODEPAGE_850 is not set +# default: +# CONFIG_FATFS_CODEPAGE_852 is not set +# default: +# CONFIG_FATFS_CODEPAGE_855 is not set +# default: +# CONFIG_FATFS_CODEPAGE_857 is not set +# default: +# CONFIG_FATFS_CODEPAGE_860 is not set +# default: +# CONFIG_FATFS_CODEPAGE_861 is not set +# default: +# CONFIG_FATFS_CODEPAGE_862 is not set +# default: +# CONFIG_FATFS_CODEPAGE_863 is not set +# default: +# CONFIG_FATFS_CODEPAGE_864 is not set +# default: +# CONFIG_FATFS_CODEPAGE_865 is not set +# default: +# CONFIG_FATFS_CODEPAGE_866 is not set +# default: +# CONFIG_FATFS_CODEPAGE_869 is not set +# default: +# CONFIG_FATFS_CODEPAGE_932 is not set +# default: +# CONFIG_FATFS_CODEPAGE_936 is not set +# default: +# CONFIG_FATFS_CODEPAGE_949 is not set +# default: +# CONFIG_FATFS_CODEPAGE_950 is not set +# default: +CONFIG_FATFS_CODEPAGE=437 +# default: +CONFIG_FATFS_MAX_LFN=255 +# default: +CONFIG_FATFS_API_ENCODING_ANSI_OEM=y +# default: +# CONFIG_FATFS_API_ENCODING_UTF_8 is not set +# default: +CONFIG_FATFS_FS_LOCK=0 +# default: +CONFIG_FATFS_TIMEOUT_MS=10000 +# default: +CONFIG_FATFS_PER_FILE_CACHE=y +# default: +# CONFIG_FATFS_USE_FASTSEEK is not set +# default: +CONFIG_FATFS_USE_STRFUNC_NONE=y +# default: +# CONFIG_FATFS_USE_STRFUNC_WITHOUT_CRLF_CONV is not set +# default: +# CONFIG_FATFS_USE_STRFUNC_WITH_CRLF_CONV is not set +# default: +CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0 +# default: +# CONFIG_FATFS_IMMEDIATE_FSYNC is not set +# default: +# CONFIG_FATFS_USE_LABEL is not set +# default: +CONFIG_FATFS_LINK_LOCK=y +# default: +CONFIG_FATFS_USE_DYN_BUFFERS=y + +# +# File system free space calculation behavior +# +# default: +CONFIG_FATFS_DONT_TRUST_FREE_CLUSTER_CNT=0 +# default: +CONFIG_FATFS_DONT_TRUST_LAST_ALLOC=0 +# end of File system free space calculation behavior +# end of FAT Filesystem support + +# +# FreeRTOS +# + +# +# Kernel +# +# default: +# CONFIG_FREERTOS_SMP is not set +# default: +CONFIG_FREERTOS_UNICORE=y +# default: +CONFIG_FREERTOS_HZ=100 +# default: +CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y +# default: +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# default: +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +# default: +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +# default: +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +# default: +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# default: +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# default: +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +# default: +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# default: +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +# default: +CONFIG_FREERTOS_USE_TIMERS=y +# default: +CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc" +# default: +# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set +# default: +CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY=y +# default: +CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x7FFFFFFF +# default: +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +# default: +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 +# default: +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +# default: +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +# default: +CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1 +# default: +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# default: +# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set +# default: +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +# default: +# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set +# end of Kernel + +# +# Port +# +# default: +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# default: +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +# default: +CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y +# default: +# CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set +# default: +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +# default: +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +# default: +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +# default: +CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y +# default: +CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y +# default: +# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set +# default: +CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +# default: +# CONFIG_FREERTOS_IN_IRAM is not set +# default: +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +# end of Port + +# +# Extra +# +# end of Extra + +# default: +CONFIG_FREERTOS_PORT=y +# default: +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +# default: +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +# default: +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +# default: +CONFIG_FREERTOS_NUMBER_OF_CORES=1 +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +# default: +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# default: +# CONFIG_HAL_ASSERTION_DISABLE is not set +# default: +# CONFIG_HAL_ASSERTION_SILENT is not set +# default: +# CONFIG_HAL_ASSERTION_ENABLE is not set +# default: +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +# default: +CONFIG_HAL_GPIO_USE_ROM_IMPL=y +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +# default: +CONFIG_HEAP_POISONING_DISABLED=y +# default: +# CONFIG_HEAP_POISONING_LIGHT is not set +# default: +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +# default: +CONFIG_HEAP_TRACING_OFF=y +# default: +# CONFIG_HEAP_TRACING_STANDALONE is not set +# default: +# CONFIG_HEAP_TRACING_TOHOST is not set +# default: +# CONFIG_HEAP_USE_HOOKS is not set +# default: +# CONFIG_HEAP_TASK_TRACKING is not set +# default: +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# default: +# CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH is not set +# end of Heap memory debugging + +# +# Log +# +# default: +CONFIG_LOG_VERSION_1=y +# default: +# CONFIG_LOG_VERSION_2 is not set +# default: +CONFIG_LOG_VERSION=1 + +# +# Log Level +# +# default: +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# default: +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# default: +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +# default: +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# default: +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# default: +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +# default: +CONFIG_LOG_DEFAULT_LEVEL=3 +# default: +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# default: +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# default: +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +# default: +CONFIG_LOG_MAXIMUM_LEVEL=3 + +# +# Level Settings +# +# default: +# CONFIG_LOG_MASTER_LEVEL is not set +# default: +CONFIG_LOG_DYNAMIC_LEVEL_CONTROL=y +# default: +# CONFIG_LOG_TAG_LEVEL_IMPL_NONE is not set +# default: +# CONFIG_LOG_TAG_LEVEL_IMPL_LINKED_LIST is not set +# default: +CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_AND_LINKED_LIST=y +# default: +# CONFIG_LOG_TAG_LEVEL_CACHE_ARRAY is not set +# default: +CONFIG_LOG_TAG_LEVEL_CACHE_BINARY_MIN_HEAP=y +# default: +CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_SIZE=31 +# end of Level Settings +# end of Log Level + +# +# Format +# +# default: +# CONFIG_LOG_COLORS is not set +# default: +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# default: +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Format + +# +# Settings +# +# default: +CONFIG_LOG_MODE_TEXT_EN=y +# default: +CONFIG_LOG_MODE_TEXT=y +# end of Settings + +# default: +CONFIG_LOG_IN_IRAM=y +# end of Log + +# +# LWIP +# +# default: +CONFIG_LWIP_ENABLE=y +# default: +CONFIG_LWIP_LOCAL_HOSTNAME="espressif" +# default: +CONFIG_LWIP_TCPIP_TASK_PRIO=18 +# default: +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# default: +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +# default: +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# default: +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# default: +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +# default: +# CONFIG_LWIP_EXTRA_IRAM_OPTIMIZATION is not set +# default: +CONFIG_LWIP_TIMERS_ONDEMAND=y +# default: +CONFIG_LWIP_ND6=y +# default: +# CONFIG_LWIP_FORCE_ROUTER_FORWARDING is not set +# default: +CONFIG_LWIP_MAX_SOCKETS=10 +# default: +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# default: +# CONFIG_LWIP_SO_LINGER is not set +# default: +CONFIG_LWIP_SO_REUSE=y +# default: +CONFIG_LWIP_SO_REUSE_RXTOALL=y +# default: +# CONFIG_LWIP_SO_RCVBUF is not set +# default: +# CONFIG_LWIP_NETBUF_RECVINFO is not set +# default: +CONFIG_LWIP_IP_DEFAULT_TTL=64 +# default: +CONFIG_LWIP_IP4_FRAG=y +# default: +CONFIG_LWIP_IP6_FRAG=y +# default: +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# default: +# CONFIG_LWIP_IP6_REASSEMBLY is not set +# default: +CONFIG_LWIP_IP_REASS_MAX_PBUFS=10 +# default: +CONFIG_LWIP_IPV6_DUP_DETECT_ATTEMPTS=1 +# default: +# CONFIG_LWIP_IP_FORWARD is not set +# default: +# CONFIG_LWIP_STATS is not set +# default: +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +# default: +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +# default: +CONFIG_LWIP_ESP_MLDV6_REPORT=y +# default: +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +# default: +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +# default: +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# default: +# CONFIG_LWIP_DHCP_DOES_ACD_CHECK is not set +# default: +# CONFIG_LWIP_DHCP_DOES_NOT_CHECK_OFFERED_IP is not set +# default: +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +# default: +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# default: +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +# default: +CONFIG_LWIP_DHCP_OPTIONS_LEN=69 +# default: +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 +# default: +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +# default: +CONFIG_LWIP_DHCPS=y +# default: +CONFIG_LWIP_DHCPS_REPORT_CLIENT_HOSTNAME=y +# default: +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +# default: +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# default: +CONFIG_LWIP_DHCPS_MAX_HOSTNAME_LEN=64 +# default: +CONFIG_LWIP_DHCPS_STATIC_ENTRIES=y +# end of DHCP server + +# default: +# CONFIG_LWIP_AUTOIP is not set +# default: +CONFIG_LWIP_IPV4=y +# default: +CONFIG_LWIP_IPV6=y +# default: +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +# default: +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# default: +# CONFIG_LWIP_IPV6_FORWARD is not set +# default: +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +# default: +# CONFIG_LWIP_NETIF_LINK_CALLBACK is not set +# default: +CONFIG_LWIP_NETIF_LOOPBACK=y +# default: +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +# default: +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +# default: +CONFIG_LWIP_MAX_LISTENING_TCP=16 +# default: +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +# default: +CONFIG_LWIP_TCP_MAXRTX=12 +# default: +CONFIG_LWIP_TCP_SYNMAXRTX=12 +# default: +CONFIG_LWIP_TCP_MSS=1440 +# default: +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +# default: +CONFIG_LWIP_TCP_MSL=60000 +# default: +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +# default: +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760 +# default: +CONFIG_LWIP_TCP_WND_DEFAULT=5760 +# default: +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +# default: +CONFIG_LWIP_TCP_ACCEPTMBOX_SIZE=6 +# default: +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +# default: +CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6 +# default: +CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4 +# default: +# CONFIG_LWIP_TCP_SACK_OUT is not set +# default: +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# default: +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# default: +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +# default: +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +# default: +CONFIG_LWIP_MAX_UDP_PCBS=16 +# default: +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# default: +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# default: +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +# default: +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +# default: +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +# default: +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# default: +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# default: +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# default: +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +# default: +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# default: +CONFIG_LWIP_IPV6_ND6_NUM_PREFIXES=5 +# default: +CONFIG_LWIP_IPV6_ND6_NUM_ROUTERS=3 +# default: +CONFIG_LWIP_IPV6_ND6_NUM_DESTINATIONS=10 +# default: +# CONFIG_LWIP_IPV6_ND6_ROUTE_INFO_OPTION_SUPPORT is not set +# default: +# CONFIG_LWIP_PPP_SUPPORT is not set +# default: +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +# default: +CONFIG_LWIP_ICMP=y +# default: +# CONFIG_LWIP_MULTICAST_PING is not set +# default: +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +# default: +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +# default: +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# default: +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +# default: +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# default: +CONFIG_LWIP_SNTP_STARTUP_DELAY=y +# default: +CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY=5000 +# end of SNTP + +# +# DNS +# +# default: +CONFIG_LWIP_DNS_MAX_HOST_IP=1 +# default: +CONFIG_LWIP_DNS_MAX_SERVERS=3 +# default: +# CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set +# default: +# CONFIG_LWIP_DNS_SETSERVER_WITH_NETIF is not set +# default: +# CONFIG_LWIP_USE_ESP_GETADDRINFO is not set +# end of DNS + +# default: +CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 +# default: +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# default: +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +# default: +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# default: +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +# default: +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# default: +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# default: +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +# default: +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# default: +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# default: +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +# default: +CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE=y +# default: +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT is not set +# default: +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM is not set +# default: +CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_NONE=y +# default: +# CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_DEFAULT is not set +# default: +# CONFIG_LWIP_HOOK_DHCP_EXTRA_OPTION_CUSTOM is not set +# default: +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# default: +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# default: +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +# default: +CONFIG_LWIP_HOOK_DNS_EXT_RESOLVE_NONE=y +# default: +# CONFIG_LWIP_HOOK_DNS_EXT_RESOLVE_CUSTOM is not set +# default: +# CONFIG_LWIP_HOOK_IP6_INPUT_NONE is not set +# default: +CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT=y +# default: +# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set +# end of Hooks + +# default: +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# + +# +# Core Configuration +# +# default: +CONFIG_MBEDTLS_VER_4_X_SUPPORT=y +# default: +# CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_NONE is not set +# default: +CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_SIZE=y +# default: +# CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_PERF is not set +# default: +CONFIG_MBEDTLS_FS_IO=y +# default: +CONFIG_MBEDTLS_THREADING_C=y +# default: +# CONFIG_MBEDTLS_THREADING_ALT is not set +# default: +CONFIG_MBEDTLS_THREADING_PTHREAD=y +# default: +CONFIG_MBEDTLS_ERROR_STRINGS=y +# default: +CONFIG_MBEDTLS_VERSION_C=y +# default: +CONFIG_MBEDTLS_HAVE_TIME=y +# default: +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# default: +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +# default: +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# default: +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# default: +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +# default: +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +# default: +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +# default: +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# default: +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# default: +# CONFIG_MBEDTLS_VERSION_FEATURES is not set +# default: +# CONFIG_MBEDTLS_DEBUG is not set +# default: +CONFIG_MBEDTLS_SELF_TEST=y +# end of Core Configuration + +# +# Certificates +# +# default: +CONFIG_MBEDTLS_X509_USE_C=y +# default: +CONFIG_MBEDTLS_PEM_PARSE_C=y +# default: +CONFIG_MBEDTLS_PEM_WRITE_C=y +# default: +CONFIG_MBEDTLS_PK_C=y +# default: +CONFIG_MBEDTLS_PK_PARSE_C=y +# default: +CONFIG_MBEDTLS_PK_WRITE_C=y +# default: +# CONFIG_MBEDTLS_X509_REMOVE_INFO is not set +# default: +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +# default: +CONFIG_MBEDTLS_X509_CRT_PARSE_C=y +# default: +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# default: +# CONFIG_MBEDTLS_X509_CREATE_C is not set +# default: +CONFIG_MBEDTLS_X509_RSASSA_PSS_SUPPORT=y +# default: +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# default: +CONFIG_MBEDTLS_ASN1_PARSE_C=y +# default: +CONFIG_MBEDTLS_ASN1_WRITE_C=y +# default: +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y + +# +# Certificate Bundle Configuration +# +# default: +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# default: +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# default: +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# default: +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +# default: +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEPRECATED_LIST is not set +# default: +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle Configuration + +# default: +# CONFIG_MBEDTLS_ALLOW_WEAK_CERTIFICATE_VERIFICATION is not set +# default: +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_CROSS_SIGNED_VERIFY is not set +# end of Certificates + +# default: +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Protocol Configuration +# +# default: +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# default: +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# default: +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# default: +CONFIG_MBEDTLS_TLS_SERVER=y +# default: +CONFIG_MBEDTLS_TLS_CLIENT=y +# default: +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# default: +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# default: +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# default: +# CONFIG_MBEDTLS_TLS_DISABLED is not set +# default: +# CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is not set +# default: +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +# default: +CONFIG_MBEDTLS_SSL_CACHE_C=y +# default: +CONFIG_MBEDTLS_SSL_ALL_ALERT_MESSAGES=y + +# +# TLS Key Exchange Configuration +# +# default: +# CONFIG_MBEDTLS_PSK_MODES is not set +# default: +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +# default: +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +# default: +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +# default: +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +# end of TLS Key Exchange Configuration + +# default: +CONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION=y +# default: +CONFIG_MBEDTLS_SSL_ALPN=y +# default: +CONFIG_MBEDTLS_SSL_MAX_FRAGMENT_LENGTH=y +# default: +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# default: +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +# default: +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +# default: +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y +# default: +# CONFIG_MBEDTLS_SSL_KEYING_MATERIAL_EXPORT is not set +# end of TLS Protocol Configuration + +# default: +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set + +# +# Symmetric Ciphers +# +# default: +CONFIG_MBEDTLS_AES_C=y +# default: +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# default: +# CONFIG_MBEDTLS_ARIA_C is not set +# default: +# CONFIG_MBEDTLS_DES_C is not set +# default: +CONFIG_MBEDTLS_CCM_C=y +# default: +CONFIG_MBEDTLS_CIPHER_MODE_CBC=y +# default: +CONFIG_MBEDTLS_CIPHER_MODE_CFB=y +# default: +CONFIG_MBEDTLS_CIPHER_MODE_CTR=y +# default: +CONFIG_MBEDTLS_CIPHER_MODE_OFB=y +# default: +CONFIG_MBEDTLS_CIPHER_MODE_XTS=y +# default: +CONFIG_MBEDTLS_GCM_C=y +# default: +# CONFIG_MBEDTLS_NIST_KW_C is not set +# default: +CONFIG_MBEDTLS_AES_ROM_TABLES=y +# default: +# CONFIG_MBEDTLS_AES_FEWER_TABLES is not set +# default: +# CONFIG_MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH is not set +# default: +CONFIG_MBEDTLS_CMAC_C=y +# end of Symmetric Ciphers + +# +# Asymmetric Ciphers +# +# default: +CONFIG_MBEDTLS_BIGNUM_C=y +# default: +CONFIG_MBEDTLS_RSA_C=y +# default: +CONFIG_MBEDTLS_ECP_C=y + +# +# Supported Curves +# +# default: +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +# default: +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +# default: +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +# default: +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +# default: +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +# default: +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +# default: +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +# default: +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +# end of Supported Curves + +# +# Elliptic Curve Ciphers Configuration +# +# default: +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +# default: +# CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM is not set +# default: +# CONFIG_MBEDTLS_DHM_C is not set +# default: +CONFIG_MBEDTLS_ECDH_C=y +# default: +# CONFIG_MBEDTLS_ECJPAKE_C is not set +# default: +CONFIG_MBEDTLS_ECDSA_C=y +# default: +CONFIG_MBEDTLS_PK_PARSE_EC_EXTENDED=y +# default: +CONFIG_MBEDTLS_PK_PARSE_EC_COMPRESSED=y +# default: +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +# default: +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +# end of Elliptic Curve Ciphers Configuration +# end of Asymmetric Ciphers + +# +# Hash functions +# +# default: +# CONFIG_MBEDTLS_RIPEMD160_C is not set +# default: +CONFIG_MBEDTLS_MD_C=y +# default: +CONFIG_MBEDTLS_MD5_C=y +# default: +CONFIG_MBEDTLS_SHA1_C=y +# default: +# CONFIG_MBEDTLS_SHA224_C is not set +# default: +CONFIG_MBEDTLS_SHA256_C=y +# default: +CONFIG_MBEDTLS_SHA384_C=y +# default: +CONFIG_MBEDTLS_SHA512_C=y +# default: +# CONFIG_MBEDTLS_SHA3_C is not set +# default: +CONFIG_MBEDTLS_ROM_MD5=y +# end of Hash functions + +# +# Hardware Acceleration +# +# default: +CONFIG_MBEDTLS_HARDWARE_SHA=y +# default: +CONFIG_MBEDTLS_HARDWARE_MPI=y +# default: +CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI=y +# default: +CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y +# default: +CONFIG_MBEDTLS_MPI_INTERRUPT_LEVEL=0 +# default: +CONFIG_MBEDTLS_HARDWARE_AES=y +# default: +# CONFIG_MBEDTLS_AES_SOFT_FALLBACK is not set +# default: +CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER=y +# default: +CONFIG_MBEDTLS_AES_USE_INTERRUPT=y +# default: +CONFIG_MBEDTLS_AES_INTERRUPT_LEVEL=0 +# default: +CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM=y +# default: +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# default: +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +# default: +CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL=y +# end of Hardware Acceleration + +# +# Entropy and Random Number Generation +# +# default: +# CONFIG_MBEDTLS_ENTROPY_FORCE_SHA256 is not set +# default: +CONFIG_MBEDTLS_CTR_DRBG_C=y +# default: +CONFIG_MBEDTLS_HMAC_DRBG_C=y +# end of Entropy and Random Number Generation + +# +# Encoding/Decoding +# +# default: +CONFIG_MBEDTLS_BASE64_C=y +# default: +CONFIG_MBEDTLS_PKCS5_C=y +# default: +CONFIG_MBEDTLS_PKCS7_C=y +# default: +CONFIG_MBEDTLS_PKCS1_V15=y +# default: +CONFIG_MBEDTLS_PKCS1_V21=y +# end of Encoding/Decoding + +# +# Stream Cipher +# +# default: +# CONFIG_MBEDTLS_CHACHA20_C is not set +# end of Stream Cipher +# end of mbedTLS + +# +# NVS +# +# default: +# CONFIG_NVS_ENCRYPTION is not set +# default: +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# default: +# CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY is not set +# default: +# CONFIG_NVS_BDL_STACK is not set +# end of NVS + +# +# OpenThread +# +# default: +# CONFIG_OPENTHREAD_ENABLED is not set + +# +# OpenThread Spinel +# +# default: +# CONFIG_OPENTHREAD_SPINEL_ONLY is not set +# end of OpenThread Spinel + +# default: +# CONFIG_OPENTHREAD_DEBUG is not set +# end of OpenThread + +# +# Protocomm +# +# default: +# CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0 is not set +# default: +# CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1 is not set +# default: +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y +# default: +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_PATCH_VERSION=y +# end of Protocomm + +# +# PThreads +# +# default: +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +# default: +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +# default: +CONFIG_PTHREAD_STACK_MIN=768 +# default: +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +# default: +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# SD Protocol Layer Configuration +# +# default: +CONFIG_SD_ENABLE_SDIO_SUPPORT=y +# end of SD Protocol Layer Configuration + +# +# MMU Config +# +# default: +CONFIG_MMU_PAGE_SIZE_64KB=y +# default: +CONFIG_MMU_PAGE_MODE="64KB" +# default: +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# Main Flash configuration +# + +# +# SPI Flash behavior when brownout +# +# default: +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +# default: +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Optional and Experimental Features (READ DOCS FIRST) +# + +# +# Features here require specific hardware (READ DOCS FIRST!) +# +# default: +# CONFIG_SPI_FLASH_AUTO_SUSPEND is not set +# default: +CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50 +# default: +# CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND is not set +# default: +# CONFIG_SPI_FLASH_FORCE_ENABLE_C6_H2_SUSPEND is not set +# default: +CONFIG_SPI_FLASH_PLACE_FUNCTIONS_IN_IRAM=y +# end of Optional and Experimental Features (READ DOCS FIRST) +# end of Main Flash configuration + +# +# SPI Flash driver +# +# default: +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# default: +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +# default: +# CONFIG_SPI_FLASH_ROM_IMPL is not set +# default: +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# default: +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# default: +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# default: +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +# default: +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +# default: +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +# default: +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +# default: +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# default: +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# default: +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# default: +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# Auto-detect flash chips +# +# default: +CONFIG_SPI_FLASH_VENDOR_XMC_SUPPORT_ENABLED=y +# default: +CONFIG_SPI_FLASH_VENDOR_GD_SUPPORT_ENABLED=y +# default: +CONFIG_SPI_FLASH_VENDOR_ISSI_SUPPORT_ENABLED=y +# default: +CONFIG_SPI_FLASH_VENDOR_MXIC_SUPPORT_ENABLED=y +# default: +CONFIG_SPI_FLASH_VENDOR_WINBOND_SUPPORT_ENABLED=y +# default: +CONFIG_SPI_FLASH_VENDOR_BOYA_SUPPORT_ENABLED=y +# default: +CONFIG_SPI_FLASH_VENDOR_TH_SUPPORT_ENABLED=y +# default: +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +# default: +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +# default: +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +# default: +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +# default: +CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y +# default: +CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y +# end of Auto-detect flash chips + +# default: +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +# default: +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +# default: +CONFIG_SPIFFS_CACHE=y +# default: +CONFIG_SPIFFS_CACHE_WR=y +# default: +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +# default: +CONFIG_SPIFFS_PAGE_CHECK=y +# default: +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# default: +# CONFIG_SPIFFS_GC_STATS is not set +# default: +CONFIG_SPIFFS_PAGE_SIZE=256 +# default: +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# default: +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +# default: +CONFIG_SPIFFS_USE_MAGIC=y +# default: +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +# default: +CONFIG_SPIFFS_META_LENGTH=4 +# default: +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# default: +# CONFIG_SPIFFS_DBG is not set +# default: +# CONFIG_SPIFFS_API_DBG is not set +# default: +# CONFIG_SPIFFS_GC_DBG is not set +# default: +# CONFIG_SPIFFS_CACHE_DBG is not set +# default: +# CONFIG_SPIFFS_CHECK_DBG is not set +# default: +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +# default: +CONFIG_WS_TRANSPORT=y +# default: +CONFIG_WS_BUFFER_SIZE=1024 +# default: +# CONFIG_WS_DYNAMIC_BUFFER is not set +# end of Websocket +# end of TCP Transport + +# +# Unity unit testing library +# +# default: +CONFIG_UNITY_ENABLE_FLOAT=y +# default: +CONFIG_UNITY_ENABLE_DOUBLE=y +# default: +# CONFIG_UNITY_ENABLE_64BIT is not set +# default: +# CONFIG_UNITY_ENABLE_COLOR is not set +# default: +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# default: +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# default: +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# Virtual file system +# +# default: +CONFIG_VFS_SUPPORT_IO=y +# default: +CONFIG_VFS_SUPPORT_DIR=y +# default: +CONFIG_VFS_SUPPORT_SELECT=y +# default: +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# default: +# CONFIG_VFS_SELECT_IN_RAM is not set +# default: +# CONFIG_VFS_SUPPORT_TERMIOS is not set +# default: +CONFIG_VFS_MAX_COUNT=8 + +# +# Host File System I/O (Semihosting) +# +# default: +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) + +# default: +CONFIG_VFS_INITIALIZE_DEV_NULL=y +# end of Virtual file system + +# +# Wear Levelling +# +# default: +# CONFIG_WL_SECTOR_SIZE_512 is not set +# default: +CONFIG_WL_SECTOR_SIZE_4096=y +# default: +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling +# end of Component config + +# default: +# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set + +# Deprecated options for backward compatibility +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +# CONFIG_NO_BLOBS is not set +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +CONFIG_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_BLUEDROID_ENABLED is not set +CONFIG_NIMBLE_ENABLED=y +CONFIG_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y +# CONFIG_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set +CONFIG_NIMBLE_PINNED_TO_CORE=0 +CONFIG_NIMBLE_TASK_STACK_SIZE=4096 +CONFIG_BT_NIMBLE_TASK_STACK_SIZE=4096 +# CONFIG_NIMBLE_ROLE_CENTRAL is not set +CONFIG_NIMBLE_ROLE_PERIPHERAL=y +CONFIG_NIMBLE_ROLE_BROADCASTER=y +# CONFIG_NIMBLE_ROLE_OBSERVER is not set +CONFIG_NIMBLE_RPA_TIMEOUT=900 +CONFIG_NIMBLE_MAX_CONNECTIONS=3 +CONFIG_NIMBLE_MAX_CCCDS=8 +CONFIG_NIMBLE_CRYPTO_STACK_MBEDTLS=y +# CONFIG_NIMBLE_HS_FLOW_CTRL is not set +CONFIG_NIMBLE_ATT_PREFERRED_MTU=256 +CONFIG_NIMBLE_L2CAP_COC_MAX_NUM=0 +CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT=12 +CONFIG_BT_NIMBLE_ACL_BUF_COUNT=24 +CONFIG_BT_NIMBLE_ACL_BUF_SIZE=255 +CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 +CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT=30 +CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT=8 +CONFIG_NIMBLE_SVC_GAP_DEVICE_NAME="nimble" +CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31 +CONFIG_NIMBLE_SVC_GAP_APPEARANCE=0 +# CONFIG_NIMBLE_MESH is not set +# CONFIG_NIMBLE_DEBUG is not set +# CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_EN is not set +CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_DIS=y +CONFIG_SW_COEXIST_ENABLE=y +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y +CONFIG_ESP_WIFI_SW_COEXIST_ENABLE=y +# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +CONFIG_GDBSTUB_SUPPORT_TASKS=y +CONFIG_GDBSTUB_MAX_TASKS=32 +# CONFIG_OTA_ALLOW_HTTP is not set +# CONFIG_ESP_SYSTEM_PD_FLASH is not set +CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP32C3_RTC_CLK_SRC_INT_RC=y +# CONFIG_ESP32C3_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32C3_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32C3_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_ESP32C3_RTC_CLK_CAL_CYCLES=1024 +CONFIG_PERIPH_CTRL_FUNC_IN_IRAM=y +CONFIG_BROWNOUT_DET=y +CONFIG_ESP32C3_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_7=y +CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_2 is not set +CONFIG_BROWNOUT_DET_LVL=7 +CONFIG_ESP32C3_BROWNOUT_DET_LVL=7 +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC_SYSTIMER=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_ESP32C3_TIME_SYSCALL_USE_SYSTIMER is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# CONFIG_ESP32C3_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +# CONFIG_REDUCE_PHY_TX_POWER is not set +# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set +CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +# CONFIG_ESP32C3_DEFAULT_CPU_FREQ_80 is not set +CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y +CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ=160 +CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=y +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_VIA_TEE=y +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=y +CONFIG_ESP32C3_MEMPROT_FEATURE=y +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=y +CONFIG_ESP32C3_MEMPROT_FEATURE_LOCK=y +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP32C3_DEBUG_OCDAWARE=y +CONFIG_IPC_TASK_STACK_SIZE=1024 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +# CONFIG_ESP32_APPTRACE_ENABLE is not set +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y +CONFIG_WPA_MBEDTLS_CRYPTO=y +CONFIG_WPA_MBEDTLS_TLS_CLIENT=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# CONFIG_WPA_11R_SUPPORT is not set +# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_L2_TO_L3_COPY is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5760 +CONFIG_TCP_WND_DEFAULT=5760 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# CONFIG_SUPPORT_TERMIOS is not set +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options diff --git a/tools/app.js b/tools/app.js new file mode 100644 index 0000000..2ca7e4d --- /dev/null +++ b/tools/app.js @@ -0,0 +1,557 @@ +// ==================== 全局状态 ==================== +let currentFile = null; +let uploadProgress = 0; +let isUploading = false; +let logFilter = 'all'; +let logEntries = []; +let logSocket = null; +let latestSystemStatus = null; + +// ==================== 工具函数 ==================== +function formatBytes(bytes) { + if (bytes < 1024) return bytes + ' B'; + if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; + return (bytes / (1024 * 1024)).toFixed(2) + ' MB'; +} + +function formatTime(date) { + return date.toTimeString().split(' ')[0]; +} + +function showToast(message, type = 'success') { + const toast = document.getElementById('toast'); + const icon = document.getElementById('toastIcon'); + const msg = document.getElementById('toastMessage'); + + toast.className = `toast ${type} show`; + icon.textContent = type === 'success' ? '✓' : type === 'error' ? '✕' : '⚠'; + msg.textContent = message; + + setTimeout(() => toast.classList.remove('show'), 3000); +} + +function getEspIp() { + return document.getElementById('espIp').value.trim() || '192.168.31.127'; +} + +function getBaseUrl() { + return `http://${getEspIp()}`; +} + +// ==================== 日志系统 ==================== +function addLog(level, tag, message) { + const logContent = document.getElementById('logContent'); + const time = formatTime(new Date()); + + const entry = { time, level, tag, message }; + logEntries.push(entry); + + if (logFilter !== 'all' && level !== logFilter) { + return; + } + + const div = document.createElement('div'); + div.className = 'log-entry'; + div.innerHTML = ` + [${time}] + ${level} + [${tag}] + ${message} + `; + + logContent.appendChild(div); + logContent.scrollTop = logContent.scrollHeight; + document.getElementById('logCount').textContent = logEntries.length; +} + +function clearLogs() { + document.getElementById('logContent').innerHTML = ''; + logEntries = []; + document.getElementById('logCount').textContent = '0'; +} + +function toggleFilter(level, btn) { + document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active')); + btn.classList.add('active'); + logFilter = level; + + const logContent = document.getElementById('logContent'); + logContent.innerHTML = ''; + logEntries.forEach(entry => { + if (level === 'all' || entry.level === level) { + const div = document.createElement('div'); + div.className = 'log-entry'; + div.innerHTML = ` + [${entry.time}] + ${entry.level} + [${entry.tag}] + ${entry.message} + `; + logContent.appendChild(div); + } + }); + logContent.scrollTop = logContent.scrollHeight; +} + +// ==================== 连接管理 ==================== +function updateConnectionUi(connected, text = null) { + const badge = document.getElementById('connectionBadge'); + const label = document.getElementById('connectionText'); + badge.className = connected ? 'badge connected' : 'badge disconnected'; + label.textContent = text || (connected ? '已连接' : '未连接'); +} + +function updateHealthUi(healthCode, freeHeap) { + const healthNames = ['正常', '警告', '危险', '关机']; + const health = healthCode !== undefined ? (healthNames[healthCode] || '未知') : '未知'; + document.getElementById('healthText').textContent = `系统${health}`; + document.getElementById('healthBadge').className = healthCode === 0 ? 'badge connected' : 'badge warning'; + if (freeHeap !== undefined) { + document.getElementById('statHeap').textContent = formatBytes(freeHeap); + } +} + +function updateSystemStatusUi(data) { + if (!data) return; + + latestSystemStatus = data; + + const wifi = data.wifi || {}; + const ota = data.ota || {}; + const healthCode = data.health; + const relayStates = { + 0: '待机', + 1: '等待握手', + 2: '握手已发', + 3: '挑战已发', + 4: '收到握手响应', + 5: '会话密钥已发', + 6: '认证完成', + 7: '大小已发', + 8: '大小确认', + 9: '接收中', + 10: '转发中', + 11: '数据包已发', + 12: 'ACK正常', + 13: '等待重发', + 14: '接收完成', + 15: '传输完成', + 16: '结束已发', + 17: 'OTA完成', + 255: '错误' + }; + + updateConnectionUi(!!wifi.connected, wifi.connected ? `${wifi.mode || 'STA'} 已连接` : `${wifi.mode || 'STA'} 未连接`); + updateHealthUi(healthCode, data.free_heap); + + // 显示固件版本 + if (data.version) { + document.getElementById('fwVersion').textContent = `v${data.version}`; + } + + document.getElementById('statTemperature').textContent = Number.isFinite(data.temperature) ? `${data.temperature.toFixed(1)}°C` : '--'; + document.getElementById('statVoltage').textContent = Number.isFinite(data.voltage) ? `${data.voltage.toFixed(2)}V` : '--'; + document.getElementById('statWifi').textContent = wifi.connected ? (wifi.ip || '已连接') : '未连接'; + document.getElementById('statSignal').textContent = (wifi.rssi !== undefined && wifi.rssi !== -127) ? `${wifi.rssi} dBm` : '--'; + document.getElementById('statHeap').textContent = data.free_heap !== undefined ? formatBytes(data.free_heap) : '--'; + document.getElementById('statMinHeap').textContent = data.min_free_heap !== undefined ? formatBytes(data.min_free_heap) : '--'; + + const total = ota.total_size || 0; + const stored = ota.stored_size || 0; + const progress = total > 0 ? Math.min(100, Math.round(stored * 100 / total)) : 0; + document.getElementById('statProgress').textContent = `${progress}%`; + document.getElementById('statRelayState').textContent = relayStates[ota.relay_state] ?? '待机'; +} + +async function testConnection() { + if (!latestSystemStatus) { + addLog('W', '连接', '暂无同步数据,请等待 1 秒自动同步'); + showToast('暂无同步数据,请稍等 1 秒', 'warning'); + return; + } + + const wifi = latestSystemStatus.wifi || {}; + const connected = !!wifi.connected; + updateSystemStatusUi(latestSystemStatus); + addLog('I', '连接', connected + ? `当前已连接:${wifi.mode || 'STA'} ${wifi.ip || ''}`.trim() + : `当前未连接:${wifi.mode || 'STA'}`); + showToast(connected ? 'ESP32 当前在线' : 'ESP32 当前未连接', connected ? 'success' : 'warning'); +} + +async function healthCheck() { + if (!latestSystemStatus) { + addLog('W', '健康', '暂无同步数据,请等待 1 秒自动同步'); + showToast('暂无同步数据,请稍等 1 秒', 'warning'); + return; + } + + updateSystemStatusUi(latestSystemStatus); + const data = latestSystemStatus; + const healthNames = ['正常', '警告', '危险', '关机']; + const health = data.health !== undefined ? (healthNames[data.health] || '未知') : '未知'; + addLog('I', '健康', `当前状态: ${health}, 空闲堆: ${data.free_heap} bytes, 温度: ${data.temperature}°C, 电压: ${data.voltage}V`); + showToast(`当前健康状态: ${health}`, 'success'); +} + +// ==================== CAN 帧发送 ==================== +async function sendCanFrame() { + const ch = parseInt(document.getElementById('canChannel').value); + const idStr = document.getElementById('canId').value.trim(); + const dlc = parseInt(document.getElementById('canDlc').value) || 8; + const dataStr = document.getElementById('canData').value.trim(); + + let extId = 0; + if (idStr.startsWith('0x') || idStr.startsWith('0X')) { + extId = parseInt(idStr, 16); + } else { + extId = parseInt(idStr, 10); + if (isNaN(extId)) extId = parseInt(idStr, 16); + } + + if (isNaN(extId)) { + showToast('ID 格式错误', 'error'); + return; + } + + let dataHex = dataStr.replace(/\s/g, ''); + if (dataHex.length % 2 !== 0) { + showToast('数据长度必须为偶数', 'error'); + return; + } + + addLog('I', 'CAN', `发送 CH${ch} ID=0x${extId.toString(16).toUpperCase()} DLC=${dlc}`); + + try { + const response = await fetch(`${getBaseUrl()}/can/send`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + ch: ch, + id: extId, + dlc: dlc, + data: dataHex + }), + signal: AbortSignal.timeout(5000) + }); + + const result = await response.json(); + + if (result.status === 'ok') { + addLog('I', 'CAN', `响应: ${result.recv || '(无数据)'} (${result.recv_len || 0}B)`); + + const respDiv = document.getElementById('canResponse'); + const respContent = document.getElementById('canRespContent'); + respDiv.style.display = 'block'; + respContent.textContent = result.recv + ? `0x${result.recv} (${result.recv_len} 字节)` + : '无响应数据'; + + showToast(`CH${ch} 发送成功`, 'success'); + } else { + addLog('E', 'CAN', `发送失败: code=${result.code}`); + showToast(`发送失败: code=${result.code}`, 'error'); + } + } catch (e) { + addLog('E', 'CAN', `发送失败: ${e.message}`); + showToast('发送失败', 'error'); + } +} + +function onTargetChipChange() { + const chip = document.getElementById('targetChip').value; + const relayBtn = document.getElementById('relayBtn'); + const esp32Actions = document.getElementById('esp32Actions'); + + if (chip === 'esp32') { + relayBtn.style.display = 'none'; + esp32Actions.style.display = 'block'; + } else { + relayBtn.style.display = ''; + esp32Actions.style.display = 'none'; + } + addLog('I', '目标', `切换到: ${chip === 'esp32' ? 'ESP32 自身升级' : 'GD32 Flash 中继'}`); +} + +function clearCanFields() { + document.getElementById('canId').value = '0x18DA00F1'; + document.getElementById('canDlc').value = '8'; + document.getElementById('canData').value = '0102030405060708'; + document.getElementById('canResponse').style.display = 'none'; +} + +// ==================== 文件处理 ==================== +function handleFileSelect(event) { + const file = event.target.files[0]; + if (file) processFile(file); +} + +document.getElementById('uploadZone').addEventListener('dragover', (e) => { + e.preventDefault(); + e.currentTarget.classList.add('dragover'); +}); + +document.getElementById('uploadZone').addEventListener('dragleave', (e) => { + e.currentTarget.classList.remove('dragover'); +}); + +document.getElementById('uploadZone').addEventListener('drop', (e) => { + e.preventDefault(); + e.currentTarget.classList.remove('dragover'); + const file = e.dataTransfer.files[0]; + if (file) processFile(file); +}); + +function processFile(file) { + currentFile = file; + const fileInfo = document.getElementById('fileInfo'); + const uploadBtn = document.getElementById('uploadBtn'); + + document.getElementById('fileName').textContent = file.name; + document.getElementById('fileType').textContent = file.name.endsWith('.hex') ? 'Intel HEX' : 'Binary'; + document.getElementById('fileSize').textContent = formatBytes(file.size); + + const chunks = Math.ceil(file.size / 4096); + document.getElementById('fileChunks').textContent = chunks + ' 包'; + + fileInfo.classList.add('visible'); + uploadBtn.disabled = false; + + addLog('I', '文件', `已选择: ${file.name} (${formatBytes(file.size)})`); + showToast('文件已选择', 'success'); +} + +function clearFile() { + currentFile = null; + document.getElementById('fileInput').value = ''; + document.getElementById('fileInfo').classList.remove('visible'); + document.getElementById('uploadBtn').disabled = true; + document.getElementById('progressSection').classList.remove('visible'); + addLog('I', '文件', '文件已清除'); +} + +// ==================== 上传固件 ==================== +async function startUpload() { + if (!currentFile || isUploading) return; + + const chip = document.getElementById('targetChip').value; + isUploading = true; + const uploadBtn = document.getElementById('uploadBtn'); + uploadBtn.disabled = true; + uploadBtn.textContent = '上传中...'; + + const progressSection = document.getElementById('progressSection'); + progressSection.classList.add('visible'); + + addLog('I', '上传', `开始上传: ${currentFile.name} → ${chip.toUpperCase()}`); + showToast(`开始上传固件到 ${chip.toUpperCase()}`, 'success'); + + try { + const arrayBuffer = await currentFile.arrayBuffer(); + const fileSize = currentFile.size; + + let body; + let url = `${getBaseUrl()}/ota/upload`; + + if (chip === 'esp32') { + const headerJson = JSON.stringify({ + type: 'esp32', + total_size: fileSize + }); + const encoder = new TextEncoder(); + const headerBytes = encoder.encode(headerJson); + const fileBytes = new Uint8Array(arrayBuffer); + + const combined = new Uint8Array(headerBytes.length + fileSize); + combined.set(headerBytes, 0); + combined.set(fileBytes, headerBytes.length); + + body = combined.buffer; + } else { + body = arrayBuffer; + } + + const xhr = new XMLHttpRequest(); + + xhr.upload.addEventListener('progress', (e) => { + if (e.lengthComputable) { + const percent = Math.round((e.loaded / e.total) * 100); + uploadProgress = percent; + document.getElementById('progressBar').style.width = percent + '%'; + document.getElementById('progressText').textContent = + `已上传 ${formatBytes(e.loaded)} / ${formatBytes(e.total)}`; + document.getElementById('progressPercent').textContent = percent + '%'; + document.getElementById('statProgress').textContent = percent + '%'; + } + }); + + xhr.addEventListener('load', () => { + isUploading = false; + uploadBtn.disabled = false; + uploadBtn.textContent = '⬆️ 上传固件'; + + if (xhr.status === 200) { + addLog('I', '上传', '固件上传完成!'); + showToast('固件上传成功', 'success'); + + if (chip === 'esp32') { + document.getElementById('esp32Actions').style.display = 'block'; + // 安全间隔:3 秒后自动调用刷写,留时间确认状态 + let countdown = 3; + addLog('I', 'OTA', `${countdown} 秒后自动调用 POST /ota/update 完成升级并重启...`); + const timer = setInterval(() => { + countdown--; + if (countdown > 0) { + addLog('I', 'OTA', `${countdown} 秒后开始刷写...`); + } else { + clearInterval(timer); + addLog('I', 'OTA', '开始刷写!'); + triggerEsp32Update(); + } + }, 1000); + } + } else { + addLog('E', '上传', `上传失败: HTTP ${xhr.status}`); + showToast('上传失败', 'error'); + } + }); + + xhr.addEventListener('error', () => { + isUploading = false; + uploadBtn.disabled = false; + uploadBtn.textContent = '⬆️ 上传固件'; + addLog('E', '上传', '上传过程发生错误'); + showToast('上传出错', 'error'); + }); + + xhr.open('POST', url); + xhr.send(body); + + } catch (e) { + addLog('E', '上传', `上传失败: ${e.message}`); + showToast('上传失败', 'error'); + isUploading = false; + uploadBtn.disabled = false; + uploadBtn.textContent = '⬆️ 上传固件'; + } +} + +// ==================== ESP32 OTA 完成升级 ==================== +async function triggerEsp32Update() { + addLog('I', 'OTA', '=== ESP32 OTA 完成,开始重启 ==='); + showToast('ESP32 正在重启...', 'success'); + + try { + const response = await fetch(`${getBaseUrl()}/ota/update`, { + method: 'POST', + signal: AbortSignal.timeout(5000) + }); + + if (response.ok) { + const data = await response.json(); + addLog('I', 'OTA', `升级完成: ${data.message}`); + addLog('I', 'OTA', 'ESP32 即将重启,新固件将生效,页面将继续通过 1 秒状态同步自动恢复显示'); + showToast('ESP32 重启中...', 'success'); + } + } catch (e) { + addLog('E', 'OTA', `升级失败: ${e.message}`); + showToast('升级失败', 'error'); + } +} + +// ==================== 触发 OTA 中继 ==================== +async function triggerRelay() { + addLog('I', 'OTA', '触发 GD32 OTA 中继...'); + showToast('正在触发 OTA 中继', 'success'); + + document.getElementById('stage1').className = 'stage active'; + document.getElementById('statRelayState').textContent = '进行中'; + + try { + const response = await fetch(`${getBaseUrl()}/ota/relay`, { + method: 'POST', + signal: AbortSignal.timeout(5000) + }); + + if (response.ok) { + addLog('I', 'OTA', 'OTA 中继已触发,正在等待 GD32 响应...'); + + setTimeout(() => { + document.getElementById('stage1').className = 'stage completed'; + document.getElementById('stage2').className = 'stage active'; + }, 2000); + + setTimeout(() => { + document.getElementById('stage2').className = 'stage completed'; + document.getElementById('stage3').className = 'stage active'; + }, 4000); + + setTimeout(() => { + document.getElementById('stage3').className = 'stage completed'; + document.getElementById('stage4').className = 'stage active'; + }, 6000); + + setTimeout(() => { + document.getElementById('stage4').className = 'stage completed'; + document.getElementById('statRelayState').textContent = '完成'; + addLog('I', 'OTA', '=== OTA 中继完成 ==='); + showToast('OTA 流程完成!', 'success'); + }, 8000); + + } else { + addLog('E', 'OTA', `触发失败: HTTP ${response.status}`); + showToast('触发失败', 'error'); + } + } catch (e) { + addLog('E', 'OTA', `触发失败: ${e.message}`); + showToast('触发失败', 'error'); + document.getElementById('statRelayState').textContent = '失败'; + } +} + +// ==================== 轮询状态 ==================== +async function pollStatus() { + try { + const response = await fetch(`${getBaseUrl()}/system/status`, { + signal: AbortSignal.timeout(3000) + }); + if (response.ok) { + const data = await response.json(); + updateSystemStatusUi(data); + } + } catch (e) { + updateConnectionUi(false, '未连接'); + } +} + +setInterval(pollStatus, 1000); + +// ==================== ESP32 实时日志拉取 ==================== +async function pollLogs() { + try { + const response = await fetch(`${getBaseUrl()}/logs`, { + signal: AbortSignal.timeout(2000) + }); + if (!response.ok) return; + const logs = await response.json(); + if (!Array.isArray(logs) || logs.length === 0) return; + + // 解析 [I][WIFI] xxx 格式 + const levelMap = { 'E': 'E', 'W': 'W', 'I': 'I', 'D': 'D' }; + logs.forEach(line => { + // 格式: [I][WIFI] message 或 [E][OTA] message + const m = line.match(/^\[([EWID])\]\[([^\]]+)\]\s*(.*)$/); + if (m) { + addLog(levelMap[m[1]] || 'I', m[2], m[3].trimEnd()); + } else { + addLog('I', 'ESP32', line.trimEnd()); + } + }); + } catch (e) { + // 静默失败,不打扰用户 + } +} + +setInterval(pollLogs, 1000); + +setTimeout(() => addLog('I', '系统', '上位机初始化完成,等待固件文件...'), 500); diff --git a/tools/index.html b/tools/index.html new file mode 100644 index 0000000..b7923b1 --- /dev/null +++ b/tools/index.html @@ -0,0 +1,282 @@ + + + + + +ESP32 OTA 中继系统 - 上位机 + + + +
+ +
+
+
📡
+
+

ESP32 OTA 中继系统

+

GD32 固件空中升级管理平台

+
+
+
+
+ + 未连接 +
+
+ + 系统正常 +
+
+ v-- +
+
+
+ + +
+ +
+ +
+
+
+
🔗
+ 连接配置 +
+
+
+ +
+ + +
+
+
+ + +
+ +
+ + +
+
+
+
📁
+ 固件文件 +
+
+ +
+
📤
+

点击或拖拽文件到此处

+

支持 .hex 和 .bin 格式

+
+ + +
+
+
+ 📄 + - +
+ +
+
+
类型: -
+
大小: -
+
数据包: -
+
+
+ +
+
+
+
+
+ 准备上传... + 0% +
+
+ +
+ + +
+ +
+ + +
+
+
+
📊
+ OTA 流程阶段 +
+
+
+
+
1️⃣
+
握手认证
+
+
+
2️⃣
+
传输准备
+
+
+
3️⃣
+
数据转发
+
+
+
4️⃣
+
完成跳转
+
+
+
+
+ + +
+ +
+
+
+
📈
+ 实时状态 +
+
+
+
+
--
+
芯片温度
+
+
+
--
+
电源电压
+
+
+
--
+
WiFi 状态
+
+
+
--
+
信号强度
+
+
+
0
+
空闲堆
+
+
+
0
+
最低空闲堆
+
+
+
0%
+
上传进度
+
+
+
待机
+
中继状态
+
+
+
+ + +
+
+
+
📨
+ CAN 帧发送 +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ +
+ + +
+
+
+
🖥️
+ 调试日志 + UDP:6666 +
+
+
+
+ 实时日志输出 +
+ + + + +
+
+
+
+ [--:--:--] + I + [系统] + 等待上位机连接... +
+
+ +
+
+
+
+
+ + +
+ ✓ + 操作成功 +
+ + + + diff --git a/tools/ota_host_web.html b/tools/ota_host_web.html deleted file mode 100644 index 2b7946a..0000000 --- a/tools/ota_host_web.html +++ /dev/null @@ -1,1385 +0,0 @@ - - - - - -ESP32 OTA 中继系统 - 上位机 - - - -
- -
-
-
📡
-
-

ESP32 OTA 中继系统

-

GD32 固件空中升级管理平台

-
-
-
-
- - 未连接 -
-
- - 系统正常 -
-
-
- - -
- -
- -
-
-
-
🔗
- 连接配置 -
-
-
- -
- - -
-
-
- -
- -
-
- -
- - -
-
-
-
📁
- 固件文件 -
-
- -
-
📤
-

点击或拖拽文件到此处

-

支持 .hex 和 .bin 格式

-
- - -
-
-
- 📄 - - -
- -
-
-
类型: -
-
大小: -
-
地址范围: -
-
数据包: -
-
-
- -
-
-
-
-
- 准备上传... - 0% -
-
- -
- - -
-
- - -
-
-
-
📊
- OTA 流程阶段 -
-
-
-
-
1️⃣
-
握手认证
-
-
-
2️⃣
-
传输准备
-
-
-
3️⃣
-
数据转发
-
-
-
4️⃣
-
完成跳转
-
-
-
-
- - -
- -
-
-
-
📈
- 实时状态 -
-
-
-
-
0
-
已发送包
-
-
-
0
-
字节数
-
-
-
0%
-
上传进度
-
-
-
待机
-
中继状态
-
-
-
- - -
-
-
-
📨
- CAN 帧发送 -
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- - -
- -
- - -
-
-
-
🖥️
- 调试日志 - UDP:6666 -
-
-
-
- 实时日志输出 -
- - - - -
-
-
-
- [--:--:--] - I - [系统] - 等待上位机连接... -
-
- -
-
-
-
-
- - -
- ✓ - 操作成功 -
- - - - \ No newline at end of file diff --git a/tools/style.css b/tools/style.css new file mode 100644 index 0000000..f6e495c --- /dev/null +++ b/tools/style.css @@ -0,0 +1,680 @@ + :root { + --bg-primary: #0a0e1a; + --bg-secondary: #111827; + --bg-card: #1a2235; + --bg-card-hover: #1f2a40; + --accent: #00d4ff; + --accent-glow: rgba(0, 212, 255, 0.3); + --accent-secondary: #7c3aed; + --success: #10b981; + --warning: #f59e0b; + --danger: #ef4444; + --text-primary: #f1f5f9; + --text-secondary: #94a3b8; + --text-muted: #64748b; + --border: #1e293b; + --gradient-1: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --gradient-2: linear-gradient(135deg, #00d4ff 0%, #7c3aed 100%); + --gradient-3: linear-gradient(135deg, #0a0e1a 0%, #1a2235 100%); + } + + * { box-sizing: border-box; margin: 0; padding: 0; } + + body { + font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background: var(--bg-primary); + color: var(--text-primary); + min-height: 100vh; + overflow-x: hidden; + } + + body::before { + content: ''; + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + background: + radial-gradient(ellipse 80% 50% at 20% 20%, rgba(0, 212, 255, 0.08) 0%, transparent 50%), + radial-gradient(ellipse 60% 40% at 80% 80%, rgba(124, 58, 237, 0.08) 0%, transparent 50%); + pointer-events: none; + z-index: 0; + } + + .container { + position: relative; + z-index: 1; + max-width: 1400px; + margin: 0 auto; + padding: 30px 40px; + } + + .header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 40px; + padding-bottom: 24px; + border-bottom: 1px solid var(--border); + } + + .logo-section { + display: flex; + align-items: center; + gap: 16px; + } + + .logo-icon { + width: 56px; + height: 56px; + background: var(--gradient-2); + border-radius: 16px; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + box-shadow: 0 8px 32px var(--accent-glow); + } + + .logo-text h1 { + font-size: 26px; + font-weight: 700; + background: var(--gradient-2); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + } + + .logo-text p { + font-size: 13px; + color: var(--text-muted); + margin-top: 4px; + } + + .status-badges { + display: flex; + gap: 12px; + } + + .badge { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 16px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 20px; + font-size: 13px; + transition: all 0.3s; + } + + .badge .dot { + width: 8px; + height: 8px; + border-radius: 50%; + animation: pulse 2s infinite; + } + + .badge.connected .dot { background: var(--success); } + .badge.disconnected .dot { background: var(--danger); animation: none; } + .badge.warning .dot { background: var(--warning); } + + @keyframes pulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.5; transform: scale(1.2); } + } + + .main-grid { + display: grid; + grid-template-columns: 420px 1fr; + gap: 24px; + } + + .left-panel { + display: flex; + flex-direction: column; + gap: 20px; + } + + .card { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 20px; + padding: 24px; + transition: all 0.3s; + } + + .card:hover { + border-color: rgba(0, 212, 255, 0.2); + box-shadow: 0 0 40px rgba(0, 212, 255, 0.05); + } + + .card-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20px; + } + + .card-title { + display: flex; + align-items: center; + gap: 10px; + font-size: 16px; + font-weight: 600; + } + + .card-title .icon { + width: 36px; + height: 36px; + background: var(--gradient-2); + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + } + + .connection-card .form-group { + margin-bottom: 16px; + } + + .form-group label { + display: block; + font-size: 12px; + color: var(--text-muted); + margin-bottom: 8px; + text-transform: uppercase; + letter-spacing: 0.5px; + } + + .input-group { + display: flex; + gap: 8px; + } + + input[type="text"] { + flex: 1; + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 10px; + padding: 12px 16px; + color: var(--text-primary); + font-size: 14px; + outline: none; + transition: all 0.3s; + } + + input[type="text"]:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-glow); + } + + .btn { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 12px 20px; + border: none; + border-radius: 10px; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.3s; + } + + .btn-primary { + background: var(--gradient-2); + color: white; + box-shadow: 0 4px 20px var(--accent-glow); + } + + .btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 8px 30px var(--accent-glow); + } + + .btn-secondary { + background: var(--bg-secondary); + color: var(--text-secondary); + border: 1px solid var(--border); + } + + .btn-secondary:hover { + background: var(--bg-card-hover); + color: var(--text-primary); + } + + .btn-success { + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + color: white; + } + + .btn-danger { + background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); + color: white; + } + + .btn:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none !important; + } + + .upload-zone { + border: 2px dashed var(--border); + border-radius: 16px; + padding: 40px 20px; + text-align: center; + cursor: pointer; + transition: all 0.3s; + position: relative; + overflow: hidden; + } + + .upload-zone::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(135deg, rgba(0, 212, 255, 0.05) 0%, rgba(124, 58, 237, 0.05) 100%); + opacity: 0; + transition: opacity 0.3s; + } + + .upload-zone:hover::before, + .upload-zone.dragover::before { + opacity: 1; + } + + .upload-zone:hover { + border-color: var(--accent); + } + + .upload-icon { + width: 64px; + height: 64px; + margin: 0 auto 16px; + background: var(--bg-secondary); + border-radius: 16px; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + } + + .upload-zone h3 { + font-size: 16px; + margin-bottom: 8px; + } + + .upload-zone p { + font-size: 13px; + color: var(--text-muted); + } + + .file-input { + display: none; + } + + .file-info { + background: var(--bg-secondary); + border-radius: 12px; + padding: 16px; + display: none; + } + + .file-info.visible { + display: block; + } + + .file-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; + } + + .file-name { + display: flex; + align-items: center; + gap: 10px; + font-size: 14px; + font-weight: 500; + } + + .file-name .icon { + font-size: 20px; + } + + .file-size { + font-size: 12px; + color: var(--text-muted); + } + + .file-meta { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + } + + .meta-item { + background: var(--bg-card); + padding: 8px 12px; + border-radius: 8px; + font-size: 12px; + } + + .meta-item span { + color: var(--text-muted); + } + + .progress-section { + margin-top: 20px; + display: none; + } + + .progress-section.visible { + display: block; + } + + .progress-bar-container { + background: var(--bg-secondary); + border-radius: 10px; + height: 12px; + overflow: hidden; + margin-bottom: 12px; + } + + .progress-bar { + height: 100%; + background: var(--gradient-2); + border-radius: 10px; + width: 0%; + transition: width 0.3s ease; + position: relative; + } + + .progress-bar::after { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; bottom: 0; + background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.2) 50%, transparent 100%); + animation: shimmer 2s infinite; + } + + @keyframes shimmer { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(100%); } + } + + .progress-info { + display: flex; + justify-content: space-between; + font-size: 12px; + color: var(--text-muted); + } + + .action-buttons { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; + margin-top: 20px; + } + + .right-panel { + display: flex; + flex-direction: column; + gap: 20px; + } + + .status-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 12px; + } + + .status-item { + background: var(--bg-secondary); + border-radius: 12px; + padding: 16px; + text-align: center; + } + + .status-item .value { + font-size: 24px; + font-weight: 700; + background: var(--gradient-2); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + } + + .status-item .label { + font-size: 11px; + color: var(--text-muted); + margin-top: 4px; + text-transform: uppercase; + } + + .log-panel { + flex: 1; + display: flex; + flex-direction: column; + min-height: 500px; + } + + .log-panel .card-body { + flex: 1; + display: flex; + flex-direction: column; + } + + .log-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 20px; + border-bottom: 1px solid var(--border); + } + + .log-filters { + display: flex; + gap: 8px; + } + + .filter-btn { + padding: 6px 12px; + border-radius: 20px; + border: 1px solid var(--border); + background: transparent; + color: var(--text-muted); + font-size: 12px; + cursor: pointer; + transition: all 0.3s; + } + + .filter-btn:hover, + .filter-btn.active { + background: var(--accent); + color: white; + border-color: var(--accent); + } + + .log-content { + flex: 1; + background: var(--bg-secondary); + border-radius: 12px; + margin: 16px; + padding: 16px; + overflow-y: auto; + max-height: 400px; + font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; + font-size: 12px; + line-height: 1.6; + } + + .log-content::-webkit-scrollbar { + width: 6px; + } + + .log-content::-webkit-scrollbar-track { + background: var(--bg-secondary); + border-radius: 3px; + } + + .log-content::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 3px; + } + + .log-entry { + padding: 4px 0; + border-bottom: 1px solid rgba(255,255,255,0.03); + display: flex; + gap: 8px; + } + + .log-time { color: var(--text-muted); } + .log-level { + font-weight: 600; + min-width: 24px; + } + .log-level.E { color: var(--danger); } + .log-level.W { color: var(--warning); } + .log-level.I { color: var(--accent); } + .log-level.D { color: var(--text-muted); } + .log-tag { color: var(--accent-secondary); } + .log-msg { color: var(--text-primary); } + + .log-footer { + padding: 12px 20px; + border-top: 1px solid var(--border); + display: flex; + justify-content: space-between; + align-items: center; + } + + .log-stats { + font-size: 12px; + color: var(--text-muted); + } + + .stage-indicator { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20px 0; + } + + .stage { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + position: relative; + flex: 1; + } + + .stage:not(:last-child)::after { + content: ''; + position: absolute; + top: 20px; + left: calc(50% + 24px); + width: calc(100% - 48px); + height: 2px; + background: var(--border); + } + + .stage.active:not(:last-child)::after, + .stage.completed:not(:last-child)::after { + background: var(--accent); + } + + .stage-icon { + width: 40px; + height: 40px; + border-radius: 50%; + background: var(--bg-secondary); + border: 2px solid var(--border); + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + transition: all 0.3s; + position: relative; + z-index: 1; + } + + .stage.active .stage-icon { + background: var(--accent); + border-color: var(--accent); + color: white; + box-shadow: 0 0 20px var(--accent-glow); + } + + .stage.completed .stage-icon { + background: var(--success); + border-color: var(--success); + color: white; + } + + .stage-label { + font-size: 11px; + color: var(--text-muted); + text-align: center; + } + + .stage.active .stage-label, + .stage.completed .stage-label { + color: var(--text-primary); + } + + .toast { + position: fixed; + bottom: 30px; + right: 30px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 12px; + padding: 16px 24px; + display: flex; + align-items: center; + gap: 12px; + box-shadow: 0 10px 40px rgba(0,0,0,0.5); + transform: translateY(100px); + opacity: 0; + transition: all 0.3s; + z-index: 1000; + } + + .toast.show { + transform: translateY(0); + opacity: 1; + } + + .toast.success { border-left: 4px solid var(--success); } + .toast.error { border-left: 4px solid var(--danger); } + .toast.warning { border-left: 4px solid var(--warning); } + + .toast-icon { + font-size: 24px; + } + + .toast-message { + font-size: 14px; + } + + @keyframes fadeIn { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } + } + + .card { + animation: fadeIn 0.5s ease forwards; + } + + .left-panel .card:nth-child(1) { animation-delay: 0.1s; } + .left-panel .card:nth-child(2) { animation-delay: 0.2s; } + .left-panel .card:nth-child(3) { animation-delay: 0.3s; } + + .right-panel .card:nth-child(1) { animation-delay: 0.15s; } + .right-panel .card:nth-child(2) { animation-delay: 0.25s; }