diff --git a/components/cmd_transport/CMakeLists.txt b/components/cmd_transport/CMakeLists.txt new file mode 100644 index 0000000..36cd264 --- /dev/null +++ b/components/cmd_transport/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "cmd_transport.c" + INCLUDE_DIRS "." + PRIV_REQUIRES console driver soc) diff --git a/components/cmd_transport/cmd_transport.c b/components/cmd_transport/cmd_transport.c new file mode 100644 index 0000000..76ba4fa --- /dev/null +++ b/components/cmd_transport/cmd_transport.c @@ -0,0 +1,131 @@ +#include "cmd_transport.h" +#include "esp_log.h" +#include "esp_console.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "soc/soc_caps.h" +#include +#include +#include + +#if SOC_USB_SERIAL_JTAG_SUPPORTED + #include "driver/usb_serial_jtag.h" +#endif + +static const char *TAG = "CMD_TP"; + +#define MAX_LISTENERS 4 +static cmd_line_handler_t s_listeners[MAX_LISTENERS] = {0}; +static int s_listener_count = 0; +static bool s_inited = false; + +void cmd_transport_register_listener(cmd_line_handler_t handler) { + if (s_listener_count < MAX_LISTENERS) { + s_listeners[s_listener_count++] = handler; + } +} + +// Trim trailing whitespace (CR, LF) +static void trim_trailing(char *s) { + int n = strlen(s); + while (n > 0 && (s[n-1] == '\r' || s[n-1] == '\n' || isspace((unsigned char)s[n-1]))) { + s[--n] = 0; + } +} + +// Dispatch line to listeners, then to ESP Console +static void dispatch_line(char *line, cmd_reply_func_t reply_func, void *reply_ctx) { + bool handled = false; + + // 1. Offer to registered listeners (e.g. wifi_cfg) + for (int i = 0; i < s_listener_count; i++) { + if (s_listeners[i] && s_listeners[i](line, reply_func, reply_ctx)) { + handled = true; + break; + } + } + + // 2. If not handled, pass to system console (for commands like 'mode_monitor') + if (!handled && strlen(line) > 0) { + int ret; + esp_err_t err = esp_console_run(line, &ret); + if (err == ESP_ERR_NOT_FOUND) { + // Unrecognized command - silent ignore or reply error + } else if (err != ESP_OK) { + ESP_LOGE(TAG, "Console run error: %s", esp_err_to_name(err)); + } + } +} + +// --- UART (stdin/stdout) Support --- +static void uart_reply(const char *msg, void *ctx) { + (void)ctx; + printf("%s", msg); + fflush(stdout); +} + +static void uart_listener_task(void *arg) { + char line[256]; + // Disable buffering + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + + while (1) { + if (fgets(line, sizeof(line), stdin)) { + trim_trailing(line); + dispatch_line(line, uart_reply, NULL); + } else { + vTaskDelay(pdMS_TO_TICKS(20)); + } + } +} + +// --- USB Serial/JTAG Support --- +#if SOC_USB_SERIAL_JTAG_SUPPORTED +static void usb_reply(const char *msg, void *ctx) { + (void)ctx; + usb_serial_jtag_write_bytes((const uint8_t*)msg, strlen(msg), pdMS_TO_TICKS(50)); +} + +static void usb_listener_task(void *arg) { + usb_serial_jtag_driver_config_t d = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(); + if (usb_serial_jtag_driver_install(&d) != ESP_OK) { + ESP_LOGE(TAG, "Failed to install USB-Serial/JTAG driver"); + vTaskDelete(NULL); + } + + char buf[256]; + size_t idx = 0; + uint8_t c; + + while (1) { + int n = usb_serial_jtag_read_bytes(&c, 1, pdMS_TO_TICKS(20)); + if (n > 0) { + if (c == '\n' || c == '\r') { + if (idx > 0) { + buf[idx] = 0; + dispatch_line(buf, usb_reply, NULL); + idx = 0; + } + } else { + if (idx < sizeof(buf) - 1) { + buf[idx++] = (char)c; + } + } + } + } +} +#endif + +void cmd_transport_init(void) { + if (s_inited) return; + s_inited = true; + + // Start UART Listener + xTaskCreatePinnedToCore(uart_listener_task, "cmd_uart", 4096, NULL, 5, NULL, tskNO_AFFINITY); + + // Start USB Listener (if supported) + #if SOC_USB_SERIAL_JTAG_SUPPORTED + xTaskCreatePinnedToCore(usb_listener_task, "cmd_usb", 4096, NULL, 5, NULL, tskNO_AFFINITY); + #endif +} diff --git a/components/cmd_transport/cmd_transport.h b/components/cmd_transport/cmd_transport.h new file mode 100644 index 0000000..d12db0d --- /dev/null +++ b/components/cmd_transport/cmd_transport.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Function pointer structure for replying to the command source + */ +typedef void (*cmd_reply_func_t)(const char *msg, void *ctx); + +/** + * @brief Callback for handling incoming lines + * * @param line The received line (null-terminated, trimmed of trailing CR/LF) + * @param reply_func Function to call to send a response back to the source + * @param reply_ctx Context pointer to pass to reply_func + * @return true if the line was consumed/handled + * @return false if the line should be passed to the next listener (or system console) + */ +typedef bool (*cmd_line_handler_t)(const char *line, cmd_reply_func_t reply_func, void *reply_ctx); + +/** + * @brief Initialize the command transport (starts UART and USB listener tasks) + */ +void cmd_transport_init(void); + +/** + * @brief Register a listener for console input + * @param handler The callback function + */ +void cmd_transport_register_listener(cmd_line_handler_t handler); + +#ifdef __cplusplus +} +#endif diff --git a/components/gps_sync/gps_sync.c b/components/gps_sync/gps_sync.c index bbb6bad..8731f6e 100644 --- a/components/gps_sync/gps_sync.c +++ b/components/gps_sync/gps_sync.c @@ -13,15 +13,11 @@ static const char *TAG = "GPS_SYNC"; -// --- INTERNAL MACROS --- #define GPS_BAUD_RATE 9600 #define UART_BUF_SIZE 1024 // --- GLOBAL STATE --- -// MUST be defined before gps_task uses it static uart_port_t gps_uart_num = UART_NUM_1; - -// GPS sync state static int64_t monotonic_offset_us = 0; static volatile int64_t last_pps_monotonic = 0; static volatile time_t next_pps_gps_second = 0; @@ -30,7 +26,7 @@ static bool use_gps_for_logs = false; static SemaphoreHandle_t sync_mutex; static volatile bool force_sync_update = true; -// PPS interrupt - captures exact monotonic time at second boundary +// PPS interrupt static void IRAM_ATTR pps_isr_handler(void* arg) { static bool onetime = true; last_pps_monotonic = esp_timer_get_time(); @@ -40,43 +36,26 @@ static void IRAM_ATTR pps_isr_handler(void* arg) { } } -// Parse GPS time from NMEA sentence +// Parse GPS time from NMEA static bool parse_gprmc(const char* nmea, struct tm* tm_out, bool* valid) { - if (strncmp(nmea, "$GPRMC", 6) != 0 && strncmp(nmea, "$GNRMC", 6) != 0) { - return false; - } - + if (strncmp(nmea, "$GPRMC", 6) != 0 && strncmp(nmea, "$GNRMC", 6) != 0) return false; char *p = strchr(nmea, ','); if (!p) return false; - - // Time field p++; int hour, min, sec; - if (sscanf(p, "%2d%2d%2d", &hour, &min, &sec) != 3) { - return false; - } - - // Status field (A=valid, V=invalid) + if (sscanf(p, "%2d%2d%2d", &hour, &min, &sec) != 3) return false; p = strchr(p, ','); if (!p) return false; p++; *valid = (*p == 'A'); - - // Skip to date field (8 commas ahead from time) for (int i = 0; i < 7; i++) { p = strchr(p, ','); if (!p) return false; p++; } - - // Date field: ddmmyy int day, month, year; - if (sscanf(p, "%2d%2d%2d", &day, &month, &year) != 3) { - return false; - } - + if (sscanf(p, "%2d%2d%2d", &day, &month, &year) != 3) return false; year += (year < 80) ? 2000 : 1900; - tm_out->tm_sec = sec; tm_out->tm_min = min; tm_out->tm_hour = hour; @@ -84,72 +63,55 @@ static bool parse_gprmc(const char* nmea, struct tm* tm_out, bool* valid) { tm_out->tm_mon = month - 1; tm_out->tm_year = year - 1900; tm_out->tm_isdst = 0; - return true; } -// Force the next GPS update to snap immediately (bypass filter) void gps_force_next_update(void) { force_sync_update = true; ESP_LOGW(TAG, "Requesting forced GPS sync update"); } -// GPS processing task static void gps_task(void* arg) { - // Buffer for UART reads (more efficient than reading 1 byte at a time) uint8_t d_buf[64]; char line[128]; int pos = 0; - static int log_counter = 0; // Counter to throttle logs + static int log_counter = 0; while (1) { - // Read up to 64 bytes with a 100ms timeout + // Using dynamically stored port int len = uart_read_bytes(gps_uart_num, d_buf, sizeof(d_buf), pdMS_TO_TICKS(100)); if (len > 0) { - // Process all bytes received in this batch for (int i = 0; i < len; i++) { uint8_t data = d_buf[i]; - if (data == '\n') { line[pos] = '\0'; - struct tm gps_tm; bool valid; if (parse_gprmc(line, &gps_tm, &valid)) { if (valid) { time_t gps_time = mktime(&gps_tm); - xSemaphoreTake(sync_mutex, portMAX_DELAY); next_pps_gps_second = gps_time + 1; xSemaphoreGive(sync_mutex); - - // Wait a bit to ensure PPS has likely fired if it was going to vTaskDelay(pdMS_TO_TICKS(300)); - xSemaphoreTake(sync_mutex, portMAX_DELAY); if (last_pps_monotonic > 0) { int64_t gps_us = (int64_t)next_pps_gps_second * 1000000LL; int64_t new_offset = gps_us - last_pps_monotonic; - if (monotonic_offset_us == 0 || force_sync_update) { monotonic_offset_us = new_offset; - if (force_sync_update) { - ESP_LOGW(TAG, "GPS sync SNAP: Offset forced to %lld us", monotonic_offset_us); + ESP_LOGW(TAG, "GPS sync SNAP: Offset forced to %" PRIi64 " us", monotonic_offset_us); force_sync_update = false; - log_counter = 0; // Ensure we see the log immediately after a snap + log_counter = 0; } } else { - // Low-pass filter: 90% old + 10% new monotonic_offset_us = (monotonic_offset_us * 9 + new_offset) / 10; } - gps_has_fix = true; - - // LOGGING THROTTLE: Only print every 60th update (approx 60 seconds) if (log_counter == 0) { - ESP_LOGI(TAG, "GPS sync: %04d-%02d-%02d %02d:%02d:%02d, offset=%lld us", + ESP_LOGI(TAG, "GPS sync: %04d-%02d-%02d %02d:%02d:%02d, offset=%" PRIi64 " us", gps_tm.tm_year + 1900, gps_tm.tm_mon + 1, gps_tm.tm_mday, gps_tm.tm_hour, gps_tm.tm_min, gps_tm.tm_sec, monotonic_offset_us); @@ -162,7 +124,6 @@ static void gps_task(void* arg) { gps_has_fix = false; } } - pos = 0; } else if (pos < sizeof(line) - 1) { line[pos++] = data; @@ -175,11 +136,9 @@ static void gps_task(void* arg) { void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps) { ESP_LOGI(TAG, "Initializing GPS sync"); - // 1. Store the UART port for the task to use gps_uart_num = config->uart_port; use_gps_for_logs = use_gps_log_timestamps; - // Ensure we start with a forced update gps_force_next_update(); if (use_gps_log_timestamps) { @@ -189,7 +148,6 @@ void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps) sync_mutex = xSemaphoreCreateMutex(); - // 2. Configure UART uart_config_t uart_config = { .baud_rate = GPS_BAUD_RATE, .data_bits = UART_DATA_8_BITS, @@ -202,14 +160,12 @@ void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps) ESP_ERROR_CHECK(uart_driver_install(config->uart_port, UART_BUF_SIZE, 0, 0, NULL, 0)); ESP_ERROR_CHECK(uart_param_config(config->uart_port, &uart_config)); - // 3. Set Pins (Dynamic Configuration) ESP_ERROR_CHECK(uart_set_pin(config->uart_port, config->tx_pin, config->rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); - // 4. Configure PPS GPIO gpio_config_t io_conf = { .intr_type = GPIO_INTR_POSEDGE, .mode = GPIO_MODE_INPUT, @@ -219,7 +175,6 @@ void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps) }; ESP_ERROR_CHECK(gpio_config(&io_conf)); - // 5. Install ISR gpio_install_isr_service(0); ESP_ERROR_CHECK(gpio_isr_handler_add(config->pps_pin, pps_isr_handler, NULL)); @@ -229,6 +184,7 @@ void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps) config->uart_port, config->rx_pin, config->tx_pin, config->pps_pin); } + gps_timestamp_t gps_get_timestamp(void) { gps_timestamp_t ts; diff --git a/components/gps_sync/gps_sync.h b/components/gps_sync/gps_sync.h index 665d6a1..1e5c10d 100644 --- a/components/gps_sync/gps_sync.h +++ b/components/gps_sync/gps_sync.h @@ -1,12 +1,9 @@ #pragma once - -#include -#include -#include #include "driver/gpio.h" #include "driver/uart.h" -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" +#include +#include +#include typedef struct { uart_port_t uart_port; @@ -16,21 +13,18 @@ typedef struct { } gps_sync_config_t; typedef struct { - int64_t monotonic_us; // Microseconds - never jumps backward - int64_t monotonic_ms; // Milliseconds - for easier logging - int64_t gps_us; // GPS UTC time in microseconds - int64_t gps_ms; // GPS UTC time in milliseconds - struct timespec mono_ts; // POSIX timespec - bool synced; // true if GPS has valid fix + int64_t monotonic_us; + int64_t monotonic_ms; + int64_t gps_us; + int64_t gps_ms; + struct timespec mono_ts; + bool synced; } gps_timestamp_t; void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps); - void gps_force_next_update(void); gps_timestamp_t gps_get_timestamp(void); int64_t gps_get_monotonic_ms(void); bool gps_is_synced(void); - -// Internal logging hooks uint32_t gps_log_timestamp(void); int gps_log_vprintf(const char *fmt, va_list args); diff --git a/components/wifi_cfg/CMakeLists.txt b/components/wifi_cfg/CMakeLists.txt index 504f7be..f16fe93 100644 --- a/components/wifi_cfg/CMakeLists.txt +++ b/components/wifi_cfg/CMakeLists.txt @@ -1,11 +1,3 @@ -idf_component_register( - SRCS "wifi_cfg.c" - INCLUDE_DIRS "." - REQUIRES - esp_wifi - esp_netif - nvs_flash - esp_event - driver - esp_driver_usb_serial_jtag -) +idf_component_register(SRCS "wifi_cfg.c" + INCLUDE_DIRS "." + PRIV_REQUIRES nvs_flash esp_wifi esp_netif driver cmd_transport) diff --git a/components/wifi_cfg/wifi_cfg.c b/components/wifi_cfg/wifi_cfg.c index a957d8f..073e743 100644 --- a/components/wifi_cfg/wifi_cfg.c +++ b/components/wifi_cfg/wifi_cfg.c @@ -1,21 +1,10 @@ -// wifi_cfg_dualmode.c — ESP-IDF v5.3.x -// Listens for CFG/END Wi‑Fi config on BOTH UART(console/COM) and USB‑Serial/JTAG concurrently. -// - UART path uses stdio (fgets on stdin) — works with /dev/ttyUSB* -// - USB path uses driver API (usb_serial_jtag_read_bytes / write_bytes) — works with /dev/ttyACM* -// - Tolerates ESP_ERR_INVALID_STATE on repeated inits -// - Supports DHCP or static IP, persists to NVS, applies immediately -// - Bandwidth options: HT20 (20MHz), HT40 (40MHz), VHT80 (80MHz, 5GHz only) -// - Power save modes: NONE (default, best for CSI), MIN/MIN_MODEM, MAX/MAX_MODEM - #include #include #include -#include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" #include "esp_log.h" #include "nvs_flash.h" #include "nvs.h" @@ -23,25 +12,15 @@ #include "esp_wifi.h" #include "esp_event.h" #include "esp_check.h" -#include "esp_event.h" -#include "driver/usb_serial_jtag.h" // direct read/write API (no VFS remap) + #include "wifi_cfg.h" - - -// wifi_cfg.c +#include "cmd_transport.h" // Now uses the transport component static const char *TAG = "wifi_cfg"; - static esp_netif_t *sta_netif = NULL; static bool cfg_dhcp = true; -static void trim(char *s){ - int n = strlen(s); - while(n>0 && (s[n-1]=='\r' || s[n-1]=='\n' || isspace((unsigned char)s[n-1]))) s[--n]=0; - while(*s && isspace((unsigned char)*s)){ - memmove(s, s+1, strlen(s)); - } -} +// --- Helper Functions (Preserved) --- static esp_err_t nvs_set_str2(nvs_handle_t h, const char *key, const char *val){ return val ? nvs_set_str(h, key, val) : nvs_erase_key(h, key); @@ -64,8 +43,7 @@ static void save_cfg(const char* ssid, const char* pass, const char* ip, const c nvs_commit(h); nvs_close(h); cfg_dhcp = dhcp; - ESP_LOGI(TAG, "Config saved to NVS: SSID=%s Mode=%s MonCh=%d Band=%s BW=%s PowerSave=%s", - ssid?ssid:"", mode?mode:"STA", mon_ch, band?band:"", bw?bw:"", powersave?powersave:"NONE"); + ESP_LOGI(TAG, "Config saved to NVS: SSID=%s Mode=%s MonCh=%d", ssid?ssid:"", mode?mode:"STA", mon_ch); } static bool load_cfg(char* ssid, size_t ssz, char* pass, size_t psz, @@ -97,36 +75,21 @@ void wifi_cfg_force_dhcp(bool enable){ cfg_dhcp = enable; } bool wifi_cfg_get_mode(char *mode, uint8_t *mon_ch) { if (!mode || !mon_ch) return false; - nvs_handle_t h; if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) { - ESP_LOGW(TAG, "Failed to open NVS for mode - defaulting to STA"); - strcpy(mode, "STA"); - *mon_ch = 36; - return false; + strcpy(mode, "STA"); *mon_ch = 36; return false; } - size_t len = 16; - esp_err_t e = nvs_get_str(h, "mode", mode, &len); - if (e != ESP_OK) { - strcpy(mode, "STA"); // Default to STA mode - } - + if (nvs_get_str(h, "mode", mode, &len) != ESP_OK) strcpy(mode, "STA"); uint8_t ch = 36; nvs_get_u8(h, "mon_ch", &ch); *mon_ch = ch; - nvs_close(h); - ESP_LOGI(TAG, "Retrieved mode from NVS: %s (MonCh=%d)", mode, ch); return true; } - -/* --- One-time net stack bring-up (thread-safe) --- */ static atomic_bool s_net_stack_ready = false; - -static esp_err_t ensure_net_stack_once(void) -{ +static esp_err_t ensure_net_stack_once(void) { bool expected = false; if (atomic_compare_exchange_strong(&s_net_stack_ready, &expected, true)) { ESP_RETURN_ON_ERROR(esp_netif_init(), TAG, "esp_netif_init"); @@ -138,236 +101,104 @@ static esp_err_t ensure_net_stack_once(void) return ESP_OK; } -/* --- One-time Wi-Fi driver init (thread-safe, idempotent) --- */ static atomic_bool s_wifi_inited = false; - -esp_err_t wifi_ensure_inited(void) -{ +esp_err_t wifi_ensure_inited(void) { bool expected = false; - if (!atomic_compare_exchange_strong(&s_wifi_inited, &expected, true)) { - // someone else already initialized (or is initializing and finished) - return ESP_OK; - } - + if (!atomic_compare_exchange_strong(&s_wifi_inited, &expected, true)) return ESP_OK; ESP_RETURN_ON_ERROR(ensure_net_stack_once(), TAG, "net stack"); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_err_t err = esp_wifi_init(&cfg); if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { - // roll back the flag so a later attempt can retry atomic_store(&s_wifi_inited, false); ESP_RETURN_ON_ERROR(err, TAG, "esp_wifi_init"); } - - // Optional: set default interface and mode now or let caller do it - // ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_STA), TAG, "set mode"); - return ESP_OK; } - static void apply_ip_static(const char* ip, const char* mask, const char* gw){ if (!sta_netif) return; - - // Validate IP strings are not empty - if (!ip || !ip[0] || !mask || !mask[0] || !gw || !gw[0]) { - ESP_LOGW(TAG, "Invalid static IP config: IP=%s MASK=%s GW=%s", - ip ? ip : "NULL", mask ? mask : "NULL", gw ? gw : "NULL"); - return; - } - + if (!ip || !ip[0] || !mask || !mask[0] || !gw || !gw[0]) return; esp_netif_ip_info_t info = {0}; esp_netif_dhcpc_stop(sta_netif); info.ip.addr = esp_ip4addr_aton(ip); info.netmask.addr = esp_ip4addr_aton(mask); info.gw.addr = esp_ip4addr_aton(gw); - - ESP_LOGI(TAG, "Setting static IP: %s, netmask: %s, gateway: %s", ip, mask, gw); - ESP_ERROR_CHECK( esp_netif_set_ip_info(sta_netif, &info) ); } bool wifi_cfg_apply_from_nvs(void) { char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0}; char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0}; - uint8_t mon_ch = 36; - bool dhcp = true; + uint8_t mon_ch = 36; bool dhcp = true; + if (!load_cfg(ssid,sizeof(ssid), pass,sizeof(pass), ip,sizeof(ip), mask,sizeof(mask), gw,sizeof(gw), band,sizeof(band), bw,sizeof(bw), powersave,sizeof(powersave), mode,sizeof(mode), &mon_ch, &dhcp)){ - ESP_LOGW(TAG, "No Wi‑Fi config in NVS"); return false; } - // Treat empty SSID as "no config" to avoid ESP_ERR_WIFI_SSID panics - if (ssid[0] == '\0') { - ESP_LOGW(TAG, "SSID in NVS is empty; treating as no Wi-Fi config"); - return false; - } - ESP_LOGI(TAG, "Applying Wi-Fi config: SSID=%s DHCP=%d IP=%s MASK=%s GW=%s Band=%s BW=%s PowerSave=%s Mode=%s MonCh=%d", - ssid, dhcp, ip, mask, gw, band, bw, powersave, mode, mon_ch); + if (ssid[0] == '\0') return false; static bool inited = false; if (!inited){ - // NVS (with recovery) - esp_err_t err = nvs_flash_init(); - if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { - nvs_flash_erase(); - err = nvs_flash_init(); - } - if (err != ESP_OK) { ESP_ERROR_CHECK(err); } - - // Netif + default event loop (tolerate already-initialized state) - do{ esp_err_t __e = esp_netif_init(); if(__e!=ESP_OK && __e!=ESP_ERR_INVALID_STATE){ ESP_ERROR_CHECK(__e);} }while(0); - if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { ESP_ERROR_CHECK(err); } - - do{ esp_err_t __e = esp_event_loop_create_default(); if(__e!=ESP_OK && __e!=ESP_ERR_INVALID_STATE){ ESP_ERROR_CHECK(__e);} }while(0); - if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { ESP_ERROR_CHECK(err); } - - if (sta_netif == NULL) { - sta_netif = esp_netif_create_default_wifi_sta(); - } - - ESP_ERROR_CHECK(err=wifi_ensure_inited()); - if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { ESP_ERROR_CHECK(err); } - + nvs_flash_init(); + ensure_net_stack_once(); + if (sta_netif == NULL) sta_netif = esp_netif_create_default_wifi_sta(); + wifi_ensure_inited(); inited = true; } - wifi_config_t wcfg = (wifi_config_t){0}; + wifi_config_t wcfg = {0}; strncpy((char*)wcfg.sta.ssid, ssid, sizeof(wcfg.sta.ssid)-1); strncpy((char*)wcfg.sta.password, pass, sizeof(wcfg.sta.password)-1); wcfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; wcfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH; - - // Set scan method to search all channels wcfg.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; - // Log and configure band preference - if (strcmp(band, "5G") == 0) { - ESP_LOGI(TAG, "Configuring for 5GHz operation"); - // For 5GHz preference, scan both but prefer 5GHz channels - wcfg.sta.channel = 0; // Scan all channels (both 2.4GHz and 5GHz) - } else { - ESP_LOGI(TAG, "Configuring for 2.4GHz operation (default)"); - wcfg.sta.channel = 0; // Scan all channels - } + if (strcmp(band, "5G") == 0) wcfg.sta.channel = 0; + else wcfg.sta.channel = 0; - ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + esp_wifi_set_mode(WIFI_MODE_STA); - // Configure WiFi protocols based on chip capabilities -#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 - // Dual-band chips (2.4GHz + 5GHz support) + // Protocol selection based on target + #if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 wifi_protocols_t protocols = { - // 2.4 GHz: b/g/n (no ax for CSI compatibility) - .ghz_2g = WIFI_PROTOCOL_11B | - WIFI_PROTOCOL_11G | - WIFI_PROTOCOL_11N, - // 5 GHz: a/n/ac/ax - .ghz_5g = WIFI_PROTOCOL_11A | - WIFI_PROTOCOL_11N | - WIFI_PROTOCOL_11AC | - WIFI_PROTOCOL_11AX, + .ghz_2g = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N, + .ghz_5g = WIFI_PROTOCOL_11A | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11AC | WIFI_PROTOCOL_11AX, }; - ESP_ERROR_CHECK( esp_wifi_set_protocols(WIFI_IF_STA, &protocols) ); -#else - // Single-band chips (2.4GHz only) - ESP32, ESP32-S2, ESP32-S3, ESP32-C3, etc. - // Use legacy API for 2.4GHz-only chips - uint8_t protocol_bitmap = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N; - ESP_ERROR_CHECK( esp_wifi_set_protocol(WIFI_IF_STA, protocol_bitmap) ); + esp_wifi_set_protocols(WIFI_IF_STA, &protocols); + #else + esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N); + #endif - // Warn if user requested 5GHz on a 2.4GHz-only chip - if (strcmp(band, "5G") == 0) { - ESP_LOGW(TAG, "5GHz requested but this chip only supports 2.4GHz - using 2.4GHz"); - } -#endif + esp_wifi_set_config(WIFI_IF_STA, &wcfg); - ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wcfg) ); + if (!dhcp && ip[0]) apply_ip_static(ip, mask, gw); + else if (sta_netif) esp_netif_dhcpc_start(sta_netif); - if (!dhcp && ip[0] && mask[0] && gw[0]){ - apply_ip_static(ip, mask, gw); - } else { - if (sta_netif) esp_netif_dhcpc_start(sta_netif); - } - - // Set bandwidth BEFORE WiFi is started -#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 - // Dual-band chips use struct-based API - wifi_bandwidths_t bandwidths = { - .ghz_2g = WIFI_BW_HT20, - .ghz_5g = WIFI_BW_HT20 - }; - - if (strcmp(bw, "VHT80") == 0) { - // 80MHz only supported on 5GHz - bandwidths.ghz_2g = WIFI_BW_HT40; // 2.4GHz fallback to 40MHz - bandwidths.ghz_5g = WIFI_BW80; // Use WIFI_BW80, not WIFI_BW_HT80 - ESP_LOGI(TAG, "Setting bandwidth to VHT80 (80MHz) for 5GHz, HT40 (40MHz) for 2.4GHz"); - } else if (strcmp(bw, "HT40") == 0) { - bandwidths.ghz_2g = WIFI_BW_HT40; - bandwidths.ghz_5g = WIFI_BW_HT40; - ESP_LOGI(TAG, "Setting bandwidth to HT40 (40MHz) for both bands"); - } else { - ESP_LOGI(TAG, "Setting bandwidth to HT20 (20MHz) for both bands"); - } - - esp_err_t bw_err = esp_wifi_set_bandwidths(WIFI_IF_STA, &bandwidths); - if (bw_err != ESP_OK) { - ESP_LOGW(TAG, "Failed to set bandwidths: %s", esp_err_to_name(bw_err)); - } -#else - // Single-band chips (2.4GHz only) use legacy API + // Bandwidth selection + #if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 + wifi_bandwidths_t bandwidths = {.ghz_2g = WIFI_BW_HT20, .ghz_5g = WIFI_BW_HT20}; + if (strcmp(bw, "VHT80") == 0) { bandwidths.ghz_2g = WIFI_BW_HT40; bandwidths.ghz_5g = WIFI_BW80; } + else if (strcmp(bw, "HT40") == 0) { bandwidths.ghz_2g = WIFI_BW_HT40; bandwidths.ghz_5g = WIFI_BW_HT40; } + esp_wifi_set_bandwidths(WIFI_IF_STA, &bandwidths); + #else wifi_bandwidth_t bandwidth = WIFI_BW_HT20; + if (strcmp(bw, "HT40") == 0) bandwidth = WIFI_BW_HT40; + esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth); + #endif - if (strcmp(bw, "VHT80") == 0) { - ESP_LOGW(TAG, "VHT80 (80MHz) not supported on 2.4GHz-only chips - using HT40 (40MHz)"); - bandwidth = WIFI_BW_HT40; - } else if (strcmp(bw, "HT40") == 0) { - bandwidth = WIFI_BW_HT40; - ESP_LOGI(TAG, "Setting bandwidth to HT40 (40MHz) for 2.4GHz"); - } else { - ESP_LOGI(TAG, "Setting bandwidth to HT20 (20MHz) for 2.4GHz"); - } + esp_wifi_start(); - esp_err_t bw_err = esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth); - if (bw_err != ESP_OK) { - ESP_LOGW(TAG, "Failed to set bandwidth: %s", esp_err_to_name(bw_err)); - } -#endif + // Power Save + wifi_ps_type_t ps_mode = WIFI_PS_NONE; + if (strcmp(powersave, "MIN") == 0) ps_mode = WIFI_PS_MIN_MODEM; + else if (strcmp(powersave, "MAX") == 0) ps_mode = WIFI_PS_MAX_MODEM; + esp_wifi_set_ps(ps_mode); - esp_err_t err2 = esp_wifi_start(); - if (err2 != ESP_OK && err2 != ESP_ERR_INVALID_STATE) { ESP_ERROR_CHECK(err2); } - - // Set power save mode based on configuration - wifi_ps_type_t ps_mode = WIFI_PS_NONE; // Default: no power save (best for CSI) - - if (strcmp(powersave, "MIN") == 0 || strcmp(powersave, "MIN_MODEM") == 0) { - ps_mode = WIFI_PS_MIN_MODEM; - ESP_LOGI(TAG, "Setting power save mode: MIN_MODEM"); - } else if (strcmp(powersave, "MAX") == 0 || strcmp(powersave, "MAX_MODEM") == 0) { - ps_mode = WIFI_PS_MAX_MODEM; - ESP_LOGI(TAG, "Setting power save mode: MAX_MODEM"); - } else { - ESP_LOGI(TAG, "Setting power save mode: NONE (best for CSI)"); - } - - err2 = esp_wifi_set_ps(ps_mode); - if (err2 != ESP_OK) { - ESP_LOGW(TAG, "Failed to set power save mode: %s", esp_err_to_name(err2)); - } - - err2 = esp_wifi_connect(); - if (err2 != ESP_OK && err2 != ESP_ERR_WIFI_NOT_INIT && err2 != ESP_ERR_INVALID_STATE) { ESP_ERROR_CHECK(err2); } + esp_wifi_connect(); return true; } -// -------------------- Dual input paths -------------------- - -typedef struct { - // emit() should write a short line back to the same channel (optional) - void (*emit)(const char *s, void *ctx); - void *ctx; - // fetch_line() should fill buf with a single line (without trailing CR/LF) and return true if a line was read - bool (*fetch_line)(char *buf, size_t sz, void *ctx); -} cfg_io_t; +// --- Command Listener Logic --- static void on_cfg_line(const char *line, char *ssid, char *pass, char *ip, char *mask, char *gw, char *band, char *bw, char *powersave, char *mode, uint8_t *mon_ch, bool *dhcp){ if (strncmp(line, "SSID:",5)==0){ strncpy(ssid, line+5, 63); ssid[63]=0; return; } @@ -383,168 +214,77 @@ static void on_cfg_line(const char *line, char *ssid, char *pass, char *ip, char if (strncmp(line, "DHCP:",5)==0){ *dhcp = atoi(line+5) ? true:false; return; } } -static void cfg_worker(const cfg_io_t *io){ - char line[160]; - char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0}; - char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0}; - uint8_t mon_ch = 36; - bool dhcp = true; - bool in_cfg = false; +static bool wifi_cfg_cmd_handler(const char *line, cmd_reply_func_t reply_func, void *reply_ctx) { + static bool in_cfg = false; + static char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0}; + static char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0}; + static uint8_t mon_ch = 36; + static bool dhcp = true; - for(;;){ - if (!io->fetch_line(line, sizeof(line), io->ctx)){ - vTaskDelay(pdMS_TO_TICKS(20)); - continue; + if (!in_cfg) { + if (strcmp(line, "CFG") == 0) { + in_cfg = true; + // Reset buffers + ssid[0]=0; pass[0]=0; ip[0]=0; mask[0]=0; gw[0]=0; + band[0]=0; bw[0]=0; powersave[0]=0; mode[0]=0; + mon_ch = 36; dhcp = true; + return true; // Handled } - trim(line); - if (!in_cfg){ - if (strcmp(line, "CFG")==0){ - in_cfg = true; - ssid[0]=pass[0]=ip[0]=mask[0]=gw[0]=0; - band[0]=bw[0]=powersave[0]=mode[0]=0; - mon_ch = 36; - dhcp = true; - } - continue; - } - if (strcmp(line, "END")==0){ - // Set defaults if not specified - if (!band[0]) strcpy(band, "2.4G"); - if (!bw[0]) strcpy(bw, "HT20"); - if (!powersave[0]) strcpy(powersave, "NONE"); - if (!mode[0]) strcpy(mode, "STA"); - - save_cfg(ssid, pass, ip, mask, gw, dhcp, band, bw, powersave, mode, mon_ch); - if (io->emit) io->emit("OK\n", io->ctx); - wifi_cfg_apply_from_nvs(); - in_cfg = false; - continue; - } - on_cfg_line(line, ssid, pass, ip, mask, gw, band, bw, powersave, mode, &mon_ch, &dhcp); + return false; // Not handled } -} -// ---- UART(stdin) path ---- -static bool uart_fetch_line(char *buf, size_t sz, void *ctx){ - (void)ctx; - if (!fgets(buf, sz, stdin)) return false; + // Inside CFG block + if (strcmp(line, "END") == 0) { + // Apply Defaults + if (!band[0]) strcpy(band, "2.4G"); + if (!bw[0]) strcpy(bw, "HT20"); + if (!powersave[0]) strcpy(powersave, "NONE"); + if (!mode[0]) strcpy(mode, "STA"); + + save_cfg(ssid, pass, ip, mask, gw, dhcp, band, bw, powersave, mode, mon_ch); + + if (reply_func) reply_func("OK\n", reply_ctx); + wifi_cfg_apply_from_nvs(); + + in_cfg = false; + return true; + } + + on_cfg_line(line, ssid, pass, ip, mask, gw, band, bw, powersave, mode, &mon_ch, &dhcp); return true; } -static void uart_emit(const char *s, void *ctx){ - (void)ctx; - fputs(s, stdout); - fflush(stdout); -} -static void cfg_listener_uart_task(void *arg){ - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); - cfg_io_t io = {.emit = uart_emit, .ctx = NULL, .fetch_line = uart_fetch_line}; - cfg_worker(&io); -} - -// ---- USB-Serial/JTAG path ---- -typedef struct { int dummy; } usb_ctx_t; -static bool usb_fetch_line(char *buf, size_t sz, void *ctx){ - (void)ctx; - static char acc[256]; - static size_t acc_len = 0; - - uint8_t tmp[64]; - int n = usb_serial_jtag_read_bytes(tmp, sizeof(tmp), pdMS_TO_TICKS(10)); - if (n <= 0){ - return false; - } - for (int i=0; i #include +#include #include #include "freertos/FreeRTOS.h" @@ -25,12 +26,14 @@ #include "csi_log.h" #include "wifi_monitor.h" #include "gps_sync.h" +// Note: cmd_transport is initialized by wifi_cfg_init, so we don't need to include it directly here unless we use it. + +static const char *TAG = "MAIN"; -// --- BOARD CONFIGURATION --- // --- Hardware Configuration --- #if defined(CONFIG_IDF_TARGET_ESP32S3) // ESP32-S3 Specific Wiring - #define RGB_LED_GPIO 48 // Standard S3 DevKit RGB pin + #define RGB_LED_GPIO 48 #define GPS_TX_PIN GPIO_NUM_5 #define GPS_RX_PIN GPIO_NUM_4 #define GPS_PPS_PIN GPIO_NUM_6 @@ -53,23 +56,17 @@ #else // Fallback / Other Chips (C6, etc.) #define RGB_LED_GPIO 8 - #define GPS_TX_PIN GPIO_NUM_24 - #define GPS_RX_PIN GPIO_NUM_23 - #define GPS_PPS_PIN GPIO_NUM_25 + #define GPS_TX_PIN GPIO_NUM_1 + #define GPS_RX_PIN GPIO_NUM_3 + #define GPS_PPS_PIN GPIO_NUM_5 #endif -static const char *TAG = "MAIN"; - - // --- WiFi Operation Mode --- typedef enum { WIFI_MODE_STA_CSI, // STA mode: Connected to AP, CSI + iperf (DEFAULT) WIFI_MODE_MONITOR // Monitor mode: Promiscuous, collapse detection } wifi_operation_mode_t; -// Note: wifi_band_mode_t is already defined in ESP-IDF's esp_wifi_types_generic.h -// Values: WIFI_BAND_MODE_2G_ONLY, WIFI_BAND_MODE_5G_ONLY, WIFI_BAND_MODE_AUTO - static wifi_operation_mode_t current_wifi_mode = WIFI_MODE_STA_CSI; static wifi_band_mode_t preferred_band = WIFI_BAND_MODE_AUTO; static uint8_t monitor_channel = 6; // Default monitor channel @@ -150,9 +147,8 @@ static void led_task(void *arg) { // --- GPS Logging Helper --- void log_collapse_event(float nav_duration_us, int rssi, int retry) { gps_timestamp_t ts = gps_get_timestamp(); - // Format: COLLAPSE,MonoMS,GpsMS,Synced,Duration,RSSI,Retry - printf("COLLAPSE,%lld,%lld,%d,%.2f,%d,%d\n", + printf("COLLAPSE,%" PRIi64 ",%" PRIi64 ",%d,%.2f,%d,%d\n", ts.monotonic_ms, ts.gps_ms, ts.synced ? 1 : 0, @@ -172,6 +168,7 @@ static void csi_cb(void *ctx, wifi_csi_info_t *info) { ESP_LOGI("CSI", "Captured %lu CSI packets", (unsigned long)s_csi_packet_count); } } + static void wifi_enable_csi_once(void) { if (s_csi_enabled) return; @@ -257,7 +254,7 @@ static void monitor_stats_task(void *arg) { wifi_collapse_stats_t stats; if (wifi_monitor_get_stats(&stats) == ESP_OK) { ESP_LOGI("MONITOR", "--- Stats: %lu frames, Retry Rate: %.2f%%, Avg NAV: %u us ---", - stats.total_frames, stats.retry_rate, stats.avg_nav); + (unsigned long)stats.total_frames, stats.retry_rate, stats.avg_nav); if (wifi_monitor_is_collapsed()) { ESP_LOGW("MONITOR", "⚠️ ⚠️ ⚠️ WiFi COLLAPSE DETECTED! ⚠️ ⚠️ ⚠️ "); @@ -274,22 +271,18 @@ esp_err_t switch_to_monitor_mode(uint8_t channel, wifi_bandwidth_t bandwidth) { return ESP_OK; } - // CRITICAL: ESP-IDF monitor/promiscuous mode is typically restricted to 20MHz - // even though the hardware supports 40MHz. Force 20MHz for monitor mode. if (bandwidth != WIFI_BW_HT20) { ESP_LOGW(TAG, "Monitor mode typically restricted to 20MHz capture width"); ESP_LOGW(TAG, "Forcing bandwidth to 20MHz (driver limitation)"); bandwidth = WIFI_BW_HT20; } - // Detect band for informational logging const char* band_str = "2.4GHz"; if (channel >= 36 && channel <= 165) { band_str = "5GHz"; } const char* bw_str = "20MHz"; - // Note: Monitor mode typically limited to 20MHz by ESP-IDF drivers ESP_LOGI(TAG, "========================================"); ESP_LOGI(TAG, "Switching to MONITOR MODE"); @@ -297,46 +290,31 @@ esp_err_t switch_to_monitor_mode(uint8_t channel, wifi_bandwidth_t bandwidth) { ESP_LOGI(TAG, " Bandwidth: %s (monitor mode limitation)", bw_str); ESP_LOGI(TAG, "========================================"); - // 1. Stop iperf if running ESP_LOGI(TAG, "Stopping iperf..."); iperf_stop(); vTaskDelay(pdMS_TO_TICKS(500)); - // 2. Disable CSI wifi_disable_csi(); vTaskDelay(pdMS_TO_TICKS(500)); - // 3. Disconnect from AP ESP_LOGI(TAG, "Disconnecting from AP..."); esp_wifi_disconnect(); vTaskDelay(pdMS_TO_TICKS(1000)); - // 4. Stop WiFi ESP_LOGI(TAG, "Stopping WiFi..."); esp_wifi_stop(); vTaskDelay(pdMS_TO_TICKS(500)); - // 5. Set to NULL mode ESP_LOGI(TAG, "Setting WiFi mode to NULL..."); esp_wifi_set_mode(WIFI_MODE_NULL); vTaskDelay(pdMS_TO_TICKS(500)); - // 6. Configure bandwidth before starting monitor mode - ESP_LOGI(TAG, "Configuring bandwidth to %s...", bw_str); - wifi_config_t wifi_config = {}; - esp_wifi_get_config(WIFI_IF_STA, &wifi_config); - - // Set bandwidth in promiscuous mode config - // Note: Bandwidth is set via wifi monitor init - - // 7. Start monitor mode ESP_LOGI(TAG, "Starting monitor mode..."); if (wifi_monitor_init(channel, monitor_frame_callback) != ESP_OK) { ESP_LOGE(TAG, "Failed to init monitor mode"); return ESP_FAIL; } - // Set bandwidth after init esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth); if (wifi_monitor_start() != ESP_OK) { @@ -349,7 +327,6 @@ esp_err_t switch_to_monitor_mode(uint8_t channel, wifi_bandwidth_t bandwidth) { current_led_state = LED_STATE_MONITORING; monitor_channel = channel; - // 8. Start stats task if (s_monitor_stats_task_handle == NULL) { xTaskCreate(monitor_stats_task, "monitor_stats", 4096, NULL, 5, &s_monitor_stats_task_handle); } @@ -384,13 +361,11 @@ esp_err_t switch_to_sta_mode(wifi_band_mode_t band_mode) { preferred_band = band_mode; - // 1. Stop monitor stats task if (s_monitor_stats_task_handle != NULL) { vTaskDelete(s_monitor_stats_task_handle); s_monitor_stats_task_handle = NULL; } - // 2. Stop monitor mode if (s_monitor_enabled) { ESP_LOGI(TAG, "Stopping monitor mode..."); wifi_monitor_stop(); @@ -398,27 +373,22 @@ esp_err_t switch_to_sta_mode(wifi_band_mode_t band_mode) { vTaskDelay(pdMS_TO_TICKS(500)); } - // 3. Set mode back to STA ESP_LOGI(TAG, "Setting WiFi mode to STA..."); esp_wifi_set_mode(WIFI_MODE_STA); vTaskDelay(pdMS_TO_TICKS(500)); - // 4. Configure band preference wifi_config_t wifi_config; esp_wifi_get_config(WIFI_IF_STA, &wifi_config); if (band_mode == WIFI_BAND_MODE_2G_ONLY) { - wifi_config.sta.channel = 0; // Scan all channels, but prefer 2.4GHz + wifi_config.sta.channel = 0; wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; - // Note: ESP-IDF doesn't have direct band filtering, but we can set channel to force band ESP_LOGI(TAG, "Configured for 2.4GHz band"); } else if (band_mode == WIFI_BAND_MODE_5G_ONLY) { - wifi_config.sta.channel = 0; // Scan all channels + wifi_config.sta.channel = 0; wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; - // The AP should be on 5GHz; connection will work if AP supports 5GHz ESP_LOGI(TAG, "Configured for 5GHz band preference"); } else { - // Auto mode - let ESP-IDF choose best band wifi_config.sta.channel = 0; wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; ESP_LOGI(TAG, "Configured for auto band selection"); @@ -426,12 +396,10 @@ esp_err_t switch_to_sta_mode(wifi_band_mode_t band_mode) { esp_wifi_set_config(WIFI_IF_STA, &wifi_config); - // 5. Start WiFi ESP_LOGI(TAG, "Starting WiFi..."); esp_wifi_start(); vTaskDelay(pdMS_TO_TICKS(500)); - // 6. Reconnect to AP ESP_LOGI(TAG, "Connecting to AP..."); esp_wifi_connect(); @@ -445,135 +413,67 @@ esp_err_t switch_to_sta_mode(wifi_band_mode_t band_mode) { ESP_LOGI(TAG, " - CSI and iperf will start after connection"); ESP_LOGI(TAG, "========================================"); - // Note: CSI and iperf will be started by event handler when IP is obtained return ESP_OK; } // --- Console Commands ---------------------------------------------- static int cmd_mode_monitor(int argc, char **argv) { - int channel = monitor_channel; // Use last channel or default - wifi_bandwidth_t bandwidth = WIFI_BW_HT20; // Default to 20MHz + int channel = monitor_channel; + wifi_bandwidth_t bandwidth = WIFI_BW_HT20; if (argc > 1) { - // Parse channel/bandwidth format: "6/20" or "36/40" char *slash = strchr(argv[1], '/'); if (slash != NULL) { - *slash = '\0'; // Split string at '/' + *slash = '\0'; channel = atoi(argv[1]); int bw = atoi(slash + 1); - - // Convert bandwidth to enum - ESP32-C5 only supports 20/40MHz switch(bw) { - case 20: - bandwidth = WIFI_BW_HT20; - break; - case 40: - bandwidth = WIFI_BW_HT40; - printf("WARNING: Monitor mode typically restricted to 20MHz by ESP-IDF drivers\n"); - printf(" 40MHz requested but will be forced to 20MHz\n"); - break; - default: - printf("Error: Invalid bandwidth %d\n", bw); - printf("ESP32-C5 hardware: 20MHz and 40MHz\n"); - printf("Monitor mode driver: 20MHz only (typical limitation)\n"); - return 1; + case 20: bandwidth = WIFI_BW_HT20; break; + case 40: bandwidth = WIFI_BW_HT40; break; + default: printf("Error: Invalid bandwidth %d\n", bw); return 1; } } else { channel = atoi(argv[1]); - // Monitor mode: always default to 20MHz (driver limitation) bandwidth = WIFI_BW_HT20; } - // Validate channel based on band - // ESP32-C5 supports WiFi 6 on 2.4GHz and 5GHz only (NO 6GHz support) bool valid = false; - const char* band = "Unknown"; - - // 2.4GHz: channels 1-14 - if (channel >= 1 && channel <= 14) { - valid = true; - band = "2.4GHz"; - - // Validate bandwidth for 2.4GHz - if (bandwidth != WIFI_BW_HT20 && bandwidth != WIFI_BW_HT40) { - printf("Error: 2.4GHz only supports 20MHz and 40MHz bandwidth\n"); - return 1; - } - } - // 5GHz: specific valid channels only - else if (channel >= 36 && channel <= 165) { - // UNII-1 and UNII-2: 36-64 (every 4 channels) - if ((channel >= 36 && channel <= 64 && (channel % 4 == 0)) || - // UNII-2 Extended: 100-144 (every 4 channels) - (channel >= 100 && channel <= 144 && (channel % 4 == 0)) || - // UNII-3: 149,153,157,161,165 - (channel >= 149 && channel <= 165 && (channel % 4 == 1))) { - valid = true; - band = "5GHz"; - } - } + if (channel >= 1 && channel <= 14) valid = true; + else if (channel >= 36 && channel <= 165) valid = true; // Simplified check if (!valid) { printf("Error: Invalid channel %d\n", channel); - printf("\nESP32-C5 supports WiFi 6 on 2.4GHz and 5GHz bands only:\n"); - printf(" 2.4GHz: 1-14 (20MHz or 40MHz)\n"); - printf(" 5GHz: 36,40,44,48,52,56,60,64,100,104,...,161,165 (20/40/80MHz)\n"); - printf("\nExamples:\n"); - printf(" mode_monitor 6/20 # 2.4GHz channel 6, 20MHz\n"); - printf(" mode_monitor 6/40 # 2.4GHz channel 6, 40MHz\n"); - printf(" mode_monitor 36/20 # 5GHz channel 36, 20MHz\n"); - printf(" mode_monitor 36/40 # 5GHz channel 36, 40MHz\n"); - printf(" mode_monitor 36/80 # 5GHz channel 36, 80MHz\n"); - printf(" mode_monitor 149 # 5GHz channel 149, default 40MHz\n"); return 1; } - - const char* bw_str = (bandwidth == WIFI_BW_HT40) ? "40MHz" : "20MHz"; - - printf("Monitoring channel %d (%s band, %s)\n", channel, band, bw_str); + printf("Monitoring channel %d\n", channel); } - esp_err_t err = switch_to_monitor_mode(channel, bandwidth); - if (err != ESP_OK) { + if (switch_to_monitor_mode(channel, bandwidth) != ESP_OK) { printf("Failed to switch to monitor mode\n"); return 1; } - return 0; } static int cmd_mode_sta(int argc, char **argv) { - wifi_band_mode_t band_mode = WIFI_BAND_MODE_AUTO; // Default to auto + wifi_band_mode_t band_mode = WIFI_BAND_MODE_AUTO; if (argc > 1) { - if (strcmp(argv[1], "2.4") == 0 || strcmp(argv[1], "2") == 0) { - band_mode = WIFI_BAND_MODE_2G_ONLY; - printf("Forcing 2.4GHz band\n"); - } else if (strcmp(argv[1], "5") == 0 || strcmp(argv[1], "5.0") == 0) { - band_mode = WIFI_BAND_MODE_5G_ONLY; - printf("Forcing 5GHz band\n"); - } else if (strcmp(argv[1], "auto") == 0) { - band_mode = WIFI_BAND_MODE_AUTO; - printf("Auto band selection (2.4GHz or 5GHz)\n"); - } else { + if (strcmp(argv[1], "2.4") == 0) band_mode = WIFI_BAND_MODE_2G_ONLY; + else if (strcmp(argv[1], "5") == 0) band_mode = WIFI_BAND_MODE_5G_ONLY; + else if (strcmp(argv[1], "auto") == 0) band_mode = WIFI_BAND_MODE_AUTO; + else { printf("Error: Invalid band '%s'\n", argv[1]); - printf("Valid options: 2.4, 5, auto\n"); - printf("Examples:\n"); - printf(" mode_sta 2.4 # Connect on 2.4GHz only\n"); - printf(" mode_sta 5 # Connect on 5GHz only\n"); - printf(" mode_sta auto # Auto select (default)\n"); return 1; } } - esp_err_t err = switch_to_sta_mode(band_mode); - if (err != ESP_OK) { + if (switch_to_sta_mode(band_mode) != ESP_OK) { printf("Failed to switch to STA mode\n"); return 1; } - - printf("Switching to STA mode (reconnecting to AP...)\n"); + printf("Switching to STA mode...\n"); return 0; } @@ -581,140 +481,62 @@ static int cmd_mode_status(int argc, char **argv) { printf("\n=== WiFi Mode Status ===\n"); printf("Current mode: %s\n", current_wifi_mode == WIFI_MODE_STA_CSI ? "STA (CSI + iperf)" : "MONITOR"); - printf("LED state: "); - switch(current_led_state) { - case LED_STATE_NO_CONFIG: printf("Yellow (No config)\n"); break; - case LED_STATE_WAITING: printf("Blue blink (Connecting)\n"); break; - case LED_STATE_CONNECTED: printf("Green (Connected)\n"); break; - case LED_STATE_MONITORING: printf("Blue solid (Monitoring)\n"); break; - case LED_STATE_FAILED: printf("Red blink (Failed)\n"); break; - } + printf("LED state: %d\n", current_led_state); if (current_wifi_mode == WIFI_MODE_STA_CSI) { printf("WiFi connected: %s\n", wifi_connected ? "Yes" : "No"); - - // Show band preference - const char* band_pref = "Auto"; - if (preferred_band == WIFI_BAND_MODE_2G_ONLY) band_pref = "2.4GHz only"; - else if (preferred_band == WIFI_BAND_MODE_5G_ONLY) band_pref = "5GHz only"; - printf("Band preference: %s\n", band_pref); - - // Show actual connected band/channel if connected - if (wifi_connected) { - wifi_ap_record_t ap_info; - if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) { - const char* band = (ap_info.primary >= 36) ? "5GHz" : "2.4GHz"; - printf("Connected band: %s (channel %d)\n", band, ap_info.primary); - - // Show bandwidth - wifi_bandwidth_t bw; - esp_wifi_get_bandwidth(WIFI_IF_STA, &bw); - const char* bw_str = "Unknown"; - if (bw == WIFI_BW_HT20) bw_str = "20MHz"; - else if (bw == WIFI_BW_HT40) bw_str = "40MHz"; - printf("Bandwidth: %s\n", bw_str); - } - } - printf("CSI enabled: %s\n", s_csi_enabled ? "Yes" : "No"); - if (s_csi_enabled) { - printf("CSI packets captured: %lu\n", (unsigned long)s_csi_packet_count); - } } else { - const char* band = (monitor_channel >= 36) ? "5GHz" : "2.4GHz"; - printf("Monitor channel: %d (%s)\n", monitor_channel, band); - - // Show monitor bandwidth - wifi_bandwidth_t bw; - esp_wifi_get_bandwidth(WIFI_IF_STA, &bw); - const char* bw_str = "Unknown"; - if (bw == WIFI_BW_HT20) bw_str = "20MHz"; - else if (bw == WIFI_BW_HT40) bw_str = "40MHz"; - printf("Monitor bandwidth: %s\n", bw_str); - - printf("Monitor enabled: %s\n", s_monitor_enabled ? "Yes" : "No"); + printf("Monitor channel: %d\n", monitor_channel); printf("Frames captured: %lu\n", (unsigned long)s_monitor_frame_count); } printf("GPS synced: %s\n", gps_is_synced() ? "Yes (+)" : "No (*)"); printf("\n"); - return 0; } static int cmd_csi_dump(int argc, char **argv) { if (current_wifi_mode != WIFI_MODE_STA_CSI) { printf("Error: CSI only available in STA mode\n"); - printf("Use 'mode_sta' to switch to STA mode first\n"); return 1; } - - if (!s_csi_enabled) { - printf("Error: CSI not enabled yet\n"); - printf("Wait for WiFi connection, or reconnect with 'mode_sta'\n"); - return 1; - } - printf("Dumping CSI data...\n"); csi_log_dump_over_uart(); - printf("CSI dump complete\n"); - return 0; } static void register_mode_commands(void) { const esp_console_cmd_t mode_monitor = { .command = "mode_monitor", - .help = "Switch to monitor mode (collapse detection)\n" - " ESP32-C5 Hardware: WiFi 6 on 2.4GHz/5GHz, 20/40MHz\n" - " Monitor Driver: Typically restricted to 20MHz capture\n" - " Usage: mode_monitor [channel[/bandwidth]]\n" - " Note: 40MHz will be forced to 20MHz (driver limitation)\n" - " Examples:\n" - " mode_monitor 6 # 2.4GHz ch 6, 20MHz\n" - " mode_monitor 6/20 # 2.4GHz ch 6, 20MHz (explicit)\n" - " mode_monitor 36 # 5GHz ch 36, 20MHz\n" - " mode_monitor 149/20 # 5GHz ch 149, 20MHz", + .help = "Switch to monitor mode", .func = &cmd_mode_monitor, }; ESP_ERROR_CHECK(esp_console_cmd_register(&mode_monitor)); const esp_console_cmd_t mode_sta = { .command = "mode_sta", - .help = "Switch to STA mode (CSI + iperf)\n" - " STA mode supports 20MHz and 40MHz (full hardware support)\n" - " Usage: mode_sta [band]\n" - " Band: 2.4, 5, auto (default)\n" - " Examples:\n" - " mode_sta # Auto band selection\n" - " mode_sta 2.4 # Connect on 2.4GHz only\n" - " mode_sta 5 # Connect on 5GHz only", + .help = "Switch to STA mode", .func = &cmd_mode_sta, }; ESP_ERROR_CHECK(esp_console_cmd_register(&mode_sta)); const esp_console_cmd_t mode_status = { .command = "mode_status", - .help = "Show current WiFi mode and status", + .help = "Show status", .func = &cmd_mode_status, }; ESP_ERROR_CHECK(esp_console_cmd_register(&mode_status)); const esp_console_cmd_t csi_dump = { .command = "csi_dump", - .help = "Dump CSI data to UART (STA mode only)", + .help = "Dump CSI data", .func = &cmd_csi_dump, }; ESP_ERROR_CHECK(esp_console_cmd_register(&csi_dump)); - - ESP_LOGI(TAG, "Mode switch commands registered:"); - ESP_LOGI(TAG, " mode_monitor [ch/bw] - Switch to monitor mode with bandwidth"); - ESP_LOGI(TAG, " mode_sta [band] - Switch to STA mode with band preference"); - ESP_LOGI(TAG, " mode_status - Show current mode"); - ESP_LOGI(TAG, " csi_dump - Dump CSI data"); } -// --- Event Handler (Connection Logic) ------------------------------ +// --- Event Handler ------------------------------------------------- static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_base == WIFI_EVENT) { @@ -733,102 +555,62 @@ static void event_handler(void* arg, esp_event_base_t event_base, } } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - if (current_wifi_mode != WIFI_MODE_STA_CSI) { - ESP_LOGW(TAG, "Got IP but not in STA mode (mode changed during connection)"); - return; - } + if (current_wifi_mode != WIFI_MODE_STA_CSI) return; ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; - ESP_LOGI(TAG, "========================================"); ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip)); - ESP_LOGI(TAG, "========================================"); wifi_connected = true; current_led_state = LED_STATE_CONNECTED; - // DEFAULT MODE: Start CSI + iperf (STA mode) - ESP_LOGI(TAG, "Starting STA mode services..."); - - // 1. Enable CSI ESP_LOGI(TAG, "Enabling CSI..."); wifi_enable_csi_once(); - // 2. Start iperf server vTaskDelay(pdMS_TO_TICKS(1000)); iperf_cfg_t cfg; memset(&cfg, 0, sizeof(cfg)); cfg.flag = IPERF_FLAG_SERVER | IPERF_FLAG_TCP; cfg.sport = 5001; iperf_start(&cfg); - ESP_LOGI(TAG, "✓ iperf TCP server started on port 5001"); + ESP_LOGI(TAG, "iperf server started"); - // 3. Optional: Schedule CSI dump for later xTaskCreate(csi_dump_task, "csi_dump_task", 4096, NULL, 5, NULL); - - ESP_LOGI(TAG, "✓ STA mode active"); - ESP_LOGI(TAG, " - CSI capture enabled"); - ESP_LOGI(TAG, " - iperf server running"); - ESP_LOGI(TAG, " - LED: Green"); - ESP_LOGI(TAG, "========================================"); - ESP_LOGI(TAG, "Console commands available:"); - ESP_LOGI(TAG, " mode_monitor [ch] - Switch to monitor mode"); - ESP_LOGI(TAG, " mode_status - Show current status"); - ESP_LOGI(TAG, " csi_dump - Dump CSI data now"); - ESP_LOGI(TAG, "========================================"); } } -// --- Main Application Entry ---------------------------------------- +// --- Main ---------------------------------------------------------- void app_main(void) { - // 1. Initialize Non-Volatile Storage (needed for WiFi config) ESP_ERROR_CHECK(nvs_flash_init()); - - // 2. Initialize Netif (TCP/IP stack) ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); - // 3. Initialize Custom Logging & LED + // Init Logging & LED ESP_ERROR_CHECK(csi_log_init()); rgb_led_init(); xTaskCreate(led_task, "led_task", 4096, NULL, 5, NULL); - // 4. Initialize GPS (Enable GPS-timestamped logs) - ESP_LOGI(TAG, "========================================"); + // Init GPS ESP_LOGI(TAG, "Initializing GPS sync..."); - - // CONFIGURATION STRUCT: Maps the correct pins based on the chip type const gps_sync_config_t gps_cfg = { .uart_port = UART_NUM_1, .tx_pin = GPS_TX_PIN, .rx_pin = GPS_RX_PIN, .pps_pin = GPS_PPS_PIN, }; - - // Pass the config and enable GPS timestamps in logs gps_sync_init(&gps_cfg, true); - ESP_LOGI(TAG, "GPS initialized on UART1 (TX:%d, RX:%d, PPS:%d)", - GPS_TX_PIN, GPS_RX_PIN, GPS_PPS_PIN); - ESP_LOGI(TAG, " - Waiting for GPS lock..."); - ESP_LOGI(TAG, " - Timestamps: (*) = not synced, (+) = GPS synced"); - ESP_LOGI(TAG, "========================================"); + ESP_LOGI(TAG, "GPS init (TX:%d, RX:%d, PPS:%d)", GPS_TX_PIN, GPS_RX_PIN, GPS_PPS_PIN); - // 5. Register WiFi Events - ESP_ERROR_CHECK(esp_event_handler_instance_register( - WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, NULL)); - ESP_ERROR_CHECK(esp_event_handler_instance_register( - IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, NULL)); + // Register Events + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, NULL)); - // 6. Initialize WiFi Configuration + // Init WiFi Config (This starts the cmd_transport listener) wifi_cfg_init(); - // 7. Initialize Serial Console (CRITICAL for console commands) + // Init Console ESP_LOGI(TAG, "Initializing console..."); - - /* Disable buffering on stdin */ setvbuf(stdin, NULL, _IONBF, 0); - - /* Initialize the console */ esp_console_config_t console_config = { .max_cmdline_args = 8, .max_cmdline_length = 256, @@ -837,90 +619,51 @@ void app_main(void) { #endif }; ESP_ERROR_CHECK(esp_console_init(&console_config)); - - /* Configure linenoise line completion library */ linenoiseSetMultiLine(1); linenoiseSetCompletionCallback(NULL); linenoiseSetHintsCallback(NULL); linenoiseHistorySetMaxLen(100); - - /* Register help command */ esp_console_register_help_command(); - - ESP_LOGI(TAG, "✓ Console initialized"); - - // 8. Register Console Commands for Mode Switching register_mode_commands(); - // 9. Apply WiFi config and connect + // Apply Config if (wifi_cfg_apply_from_nvs()) { has_config = true; current_led_state = LED_STATE_WAITING; - ESP_LOGI(TAG, "========================================"); - ESP_LOGI(TAG, "WiFi config loaded. Connecting..."); + ESP_LOGI(TAG, "WiFi config loaded."); - // Check if device is configured for MONITOR mode char mode[16] = {0}; uint8_t mon_ch = 36; if (wifi_cfg_get_mode(mode, &mon_ch)) { if (strcmp(mode, "MONITOR") == 0) { - ESP_LOGI(TAG, "MODE: MONITOR (collapse detection)"); - ESP_LOGI(TAG, "Monitor Channel: %d", mon_ch); - ESP_LOGI(TAG, "Will switch to monitor mode after WiFi connects..."); - - // Allocate channel parameter for task + ESP_LOGI(TAG, "MODE: MONITOR (Channel %d)", mon_ch); uint8_t *ch_param = malloc(sizeof(uint8_t)); *ch_param = mon_ch; - - // Create task to switch to monitor mode after connection xTaskCreate(auto_monitor_task, "auto_monitor", 4096, ch_param, 5, NULL); } else { - ESP_LOGI(TAG, "MODE: STA (CSI + iperf)"); + ESP_LOGI(TAG, "MODE: STA"); } - } else { - ESP_LOGI(TAG, "DEFAULT MODE: STA (CSI + iperf)"); } - ESP_LOGI(TAG, "========================================"); } else { has_config = false; current_led_state = LED_STATE_NO_CONFIG; - ESP_LOGI(TAG, "========================================"); ESP_LOGI(TAG, "No WiFi config found."); - ESP_LOGI(TAG, "LED: Yellow"); - ESP_LOGI(TAG, "Use CLI command: wifi_config_set "); - ESP_LOGI(TAG, "========================================"); } - - ESP_LOGI(TAG, "========================================"); - ESP_LOGI(TAG, "Initialization complete"); - ESP_LOGI(TAG, "Console commands available (no interactive prompt)"); - ESP_LOGI(TAG, "========================================"); - - // app_main() returns - device runs autonomously } -// --- Auto-Monitor Mode Task (switches to monitor mode after WiFi connects) --- static void auto_monitor_task(void *arg) { uint8_t channel = *(uint8_t*)arg; - free(arg); // Free the allocated channel parameter + free(arg); - // Wait for WiFi connection (LED will be green) ESP_LOGI(TAG, "Waiting for WiFi connection before switching to monitor mode..."); while (current_led_state != LED_STATE_CONNECTED) { vTaskDelay(pdMS_TO_TICKS(500)); } - // Wait additional 2 seconds for GPS sync ESP_LOGI(TAG, "WiFi connected, waiting for GPS sync..."); vTaskDelay(pdMS_TO_TICKS(2000)); ESP_LOGI(TAG, "Auto-switching to MONITOR mode on channel %d...", channel); - esp_err_t err = switch_to_monitor_mode(channel, WIFI_BW_HT20); - if (err == ESP_OK) { - ESP_LOGI(TAG, "✓ Monitor mode activated"); - } else { - ESP_LOGE(TAG, "✗ Failed to switch to monitor mode: %s", esp_err_to_name(err)); - } - + switch_to_monitor_mode(channel, WIFI_BW_HT20); vTaskDelete(NULL); } diff --git a/partitions_c5.csv b/partitions_c5.csv new file mode 100644 index 0000000..93e97bb --- /dev/null +++ b/partitions_c5.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, , 0x4000, +otadata, data, ota, , 0x2000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 2M, +storage, data, spiffs, , 5M, \ No newline at end of file diff --git a/partitions_esp32.csv b/partitions_esp32.csv new file mode 100644 index 0000000..9573d68 --- /dev/null +++ b/partitions_esp32.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, , 0x4000, +otadata, data, ota, , 0x2000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 1536K, +storage, data, spiffs, , 0x250000, diff --git a/partitions_s3.csv b/partitions_s3.csv new file mode 100644 index 0000000..1515d38 --- /dev/null +++ b/partitions_s3.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, , 0x4000, +otadata, data, ota, , 0x2000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 2M, +storage, data, spiffs, , 13M, \ No newline at end of file diff --git a/sdkconfig.defaults.c5 b/sdkconfig.defaults.c5 new file mode 100644 index 0000000..adea6e3 --- /dev/null +++ b/sdkconfig.defaults.c5 @@ -0,0 +1,34 @@ +# ESP32-C5 - 8MB Flash +# --- Hardware & Partitions --- +CONFIG_IDF_TARGET="esp32c5" +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_c5.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_c5.csv" + +# --- Wi-Fi & CSI --- +CONFIG_ESP_WIFI_CSI_ENABLED=y +# Ensure we have enough RX buffers for promiscuous mode/CSI +CONFIG_ESP_WIFI_RX_BA_WIN=32 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64 + +# --- System Stability --- +# Optimize for size to leave more room for CSV logs +CONFIG_COMPILER_OPTIMIZATION_SIZE=y + +# Increase stack sizes to prevent overflows during heavy CSI traffic +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=6144 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 +CONFIG_FREERTOS_ISR_STACKSIZE=2048 + +# 1000Hz (1ms) is standard high-performance. 10kHz is usually overkill. +CONFIG_FREERTOS_HZ=1000 + +# --- Console --- +# Increase console buffer for pasting large config blocks +CONFIG_CONSOLE_UART_RX_BUF_SIZE=1024 + +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_c5.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_c5.csv" diff --git a/sdkconfig.defaults.esp32 b/sdkconfig.defaults.esp32 new file mode 100644 index 0000000..a19a1eb --- /dev/null +++ b/sdkconfig.defaults.esp32 @@ -0,0 +1,24 @@ +# ESP32 - 4MB Flash +# --- Hardware & Partitions --- +CONFIG_IDF_TARGET="esp32" +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_esp32.csv" + +# --- Wi-Fi & CSI --- +CONFIG_ESP_WIFI_CSI_ENABLED=y +CONFIG_ESP_WIFI_RX_BA_WIN=32 +# FIX: Increase static buffers to support BA_WIN=32 (Rule: BA_WIN <= 2 * STATIC) +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64 + +# --- System Stability --- +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=6144 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 +CONFIG_FREERTOS_ISR_STACKSIZE=2048 +CONFIG_FREERTOS_HZ=1000 + +# --- Console --- +CONFIG_CONSOLE_UART_RX_BUF_SIZE=1024 diff --git a/sdkconfig.defaults.s3 b/sdkconfig.defaults.s3 new file mode 100644 index 0000000..07531c7 --- /dev/null +++ b/sdkconfig.defaults.s3 @@ -0,0 +1,24 @@ +# ESP32-S3 - 16MB Flash +# --- Hardware & Partitions --- +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_s3.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_s3.csv" + +# --- Wi-Fi & CSI --- +CONFIG_ESP_WIFI_CSI_ENABLED=y +CONFIG_ESP_WIFI_RX_BA_WIN=32 +# FIX: Increase static buffers +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64 + +# --- System Stability --- +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=6144 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 +CONFIG_FREERTOS_ISR_STACKSIZE=2048 +CONFIG_FREERTOS_HZ=1000 + +# --- Console --- +CONFIG_CONSOLE_UART_RX_BUF_SIZE=1024 \ No newline at end of file