From fa3e8509fb40e6c785e12747a9d78fa7a09350c7 Mon Sep 17 00:00:00 2001 From: Robert McMahon Date: Tue, 16 Dec 2025 11:56:31 -0800 Subject: [PATCH] up to build for console work --- components/app_console/CMakeLists.txt | 3 +- components/app_console/app_console.c | 198 +++++++----- components/app_console/app_console.h | 3 +- components/cmd_transport/CMakeLists.txt | 3 - components/cmd_transport/cmd_transport.c | 138 -------- components/cmd_transport/cmd_transport.h | 37 --- components/wifi_cfg/CMakeLists.txt | 2 +- components/wifi_cfg/wifi_cfg.c | 386 +++++------------------ components/wifi_cfg/wifi_cfg.h | 52 +-- main/CMakeLists.txt | 26 +- main/board_config.h | 76 +++-- main/main.c | 173 ++++------ 12 files changed, 319 insertions(+), 778 deletions(-) delete mode 100644 components/cmd_transport/CMakeLists.txt delete mode 100644 components/cmd_transport/cmd_transport.c delete mode 100644 components/cmd_transport/cmd_transport.h diff --git a/components/app_console/CMakeLists.txt b/components/app_console/CMakeLists.txt index 7d08ba6..a64ac6b 100644 --- a/components/app_console/CMakeLists.txt +++ b/components/app_console/CMakeLists.txt @@ -1,4 +1,3 @@ idf_component_register(SRCS "app_console.c" INCLUDE_DIRS "." - REQUIRES console - PRIV_REQUIRES wifi_controller csi_manager status_led gps_sync esp_wifi iperf) + PRIV_REQUIRES console wifi_cfg iperf) diff --git a/components/app_console/app_console.c b/components/app_console/app_console.c index 4fd7f63..409dc82 100644 --- a/components/app_console/app_console.c +++ b/components/app_console/app_console.c @@ -2,111 +2,161 @@ #include "esp_console.h" #include "esp_log.h" #include "argtable3/argtable3.h" -#include -#include -#include - -// Dependencies -#include "wifi_controller.h" -#include "status_led.h" -#include "gps_sync.h" +#include "wifi_cfg.h" #include "iperf.h" +#include -#ifdef CONFIG_ESP_WIFI_CSI_ENABLED -#include "csi_manager.h" -#endif - -// --- Command Handlers --- +// ============================================================================ +// COMMAND: iperf +// ============================================================================ +static struct { + struct arg_lit *start; + struct arg_lit *stop; + struct arg_lit *status; + struct arg_int *pps; + struct arg_lit *help; + struct arg_end *end; +} iperf_args; static int cmd_iperf(int argc, char **argv) { - if (argc < 2) { - printf("Usage: iperf \n"); + int nerrors = arg_parse(argc, argv, (void **)&iperf_args); + if (nerrors > 0) { + arg_print_errors(stderr, iperf_args.end, argv[0]); return 1; } - if (strcmp(argv[1], "start") == 0) { - iperf_cfg_t cfg = { .time = 0 }; // Infinite - iperf_start(&cfg); - // iperf_start already logs "IPERF_STARTED" via printf in iperf.c, - // but keeping it here is fine/redundant. - // To be safe and clean, we rely on iperf.c's output or just return success. + if (iperf_args.help->count > 0) { + printf("Usage: iperf [start|stop|status] [--pps ]\n"); return 0; + } - } else if (strcmp(argv[1], "stop") == 0) { + if (iperf_args.stop->count > 0) { iperf_stop(); return 0; + } - } else if (strcmp(argv[1], "pps") == 0) { - // Syntax: iperf pps 100 - if (argc < 3) { - printf("Error: Missing value. Usage: iperf pps \n"); - return 1; + if (iperf_args.pps->count > 0) { + int val = iperf_args.pps->ival[0]; + if (val > 0) { + iperf_set_pps((uint32_t)val); + } else { + printf("Error: PPS must be > 0\n"); } - int pps = atoi(argv[2]); - if (pps <= 0) { - printf("Error: Invalid PPS.\n"); - return 1; - } - iperf_set_pps((uint32_t)pps); - // iperf_set_pps prints "IPERF_PPS_UPDATED: ..." return 0; + } - } else if (strcmp(argv[1], "status") == 0) { - // [FIXED] Use the new API to print detailed stats + if (iperf_args.status->count > 0) { iperf_print_status(); return 0; } - printf("Error: Unknown subcommand '%s'.\n", argv[1]); - return 1; + if (iperf_args.start->count > 0) { + // Start using saved NVS config + iperf_cfg_t cfg = { .time = 0 }; + iperf_start(&cfg); + return 0; + } + + return 0; } -static int cmd_mode_monitor(int argc, char **argv) { - int channel = wifi_ctl_get_monitor_channel(); - if (argc > 1) channel = atoi(argv[1]); - if (wifi_ctl_switch_to_monitor(channel, WIFI_BW_HT20) != ESP_OK) { - printf("Failed to switch to monitor mode\n"); +static void register_iperf_cmd(void) { + iperf_args.start = arg_lit0(NULL, "start", "Start iperf traffic"); + iperf_args.stop = arg_lit0(NULL, "stop", "Stop iperf traffic"); + iperf_args.status = arg_lit0(NULL, "status", "Show current statistics"); + iperf_args.pps = arg_int0(NULL, "pps", "", "Set packets per second"); + iperf_args.help = arg_lit0(NULL, "help", "Show help"); + iperf_args.end = arg_end(20); + + const esp_console_cmd_t cmd = { + .command = "iperf", + .help = "Control iperf traffic generator", + .hint = NULL, + .func = &cmd_iperf, + .argtable = &iperf_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + +// ============================================================================ +// COMMAND: wifi_config +// ============================================================================ +static struct { + struct arg_str *ssid; + struct arg_str *pass; + struct arg_str *ip; + struct arg_lit *dhcp; + struct arg_lit *help; + struct arg_end *end; +} wifi_args; + +static int cmd_wifi_config(int argc, char **argv) { + int nerrors = arg_parse(argc, argv, (void **)&wifi_args); + if (nerrors > 0) { + arg_print_errors(stderr, wifi_args.end, argv[0]); return 1; } - return 0; -} -static int cmd_mode_sta(int argc, char **argv) { - if (wifi_ctl_switch_to_sta(WIFI_BAND_MODE_AUTO) != ESP_OK) { - printf("Failed to switch to STA mode\n"); + if (wifi_args.help->count > 0) { + printf("Usage: wifi_config -s -p [-i ] [-d]\n"); + return 0; + } + + if (wifi_args.ssid->count == 0) { + printf("Error: SSID is required (-s)\n"); return 1; } + + const char* ssid = wifi_args.ssid->sval[0]; + const char* pass = (wifi_args.pass->count > 0) ? wifi_args.pass->sval[0] : ""; + + const char* ip = (wifi_args.ip->count > 0) ? wifi_args.ip->sval[0] : NULL; + bool dhcp = (wifi_args.dhcp->count > 0); + + printf("Saving WiFi Config: SSID='%s' DHCP=%d\n", ssid, dhcp); + + wifi_cfg_set_credentials(ssid, pass); + + if (ip) { + char mask[] = "255.255.255.0"; + char gw[32]; + + // FIXED: Use strlcpy instead of strncpy to prevent truncation warnings + strlcpy(gw, ip, sizeof(gw)); + + char *last_dot = strrchr(gw, '.'); + if (last_dot) strcpy(last_dot, ".1"); + + wifi_cfg_set_static_ip(ip, mask, gw); + wifi_cfg_set_dhcp(false); + } else { + wifi_cfg_set_dhcp(dhcp); + } + + printf("Config saved. Rebooting to apply...\n"); + esp_restart(); return 0; } -static int cmd_mode_status(int argc, char **argv) { - wifi_ctl_mode_t mode = wifi_ctl_get_mode(); - printf("\n=== WiFi Mode Status ===\n"); - printf("Current mode: %s\n", mode == WIFI_CTL_MODE_STA ? "STA" : "MONITOR"); - printf("LED state: %d\n", status_led_get_state()); - printf("GPS synced: %s\n", gps_is_synced() ? "Yes" : "No"); - return 0; -} +static void register_wifi_cmd(void) { + wifi_args.ssid = arg_str0("s", "ssid", "", "WiFi SSID"); + wifi_args.pass = arg_str0("p", "password", "", "WiFi Password"); + wifi_args.ip = arg_str0("i", "ip", "", "Static IP"); + wifi_args.dhcp = arg_lit0("d", "dhcp", "Enable DHCP"); + wifi_args.help = arg_lit0("h", "help", "Show help"); + wifi_args.end = arg_end(20); -static int cmd_csi_dump(int argc, char **argv) { -#ifdef CONFIG_ESP_WIFI_CSI_ENABLED - csi_mgr_schedule_dump(); -#else - printf("Error: CSI feature is disabled in this firmware build.\n"); -#endif - return 0; + const esp_console_cmd_t cmd = { + .command = "wifi_config", + .help = "Configure WiFi credentials", + .hint = NULL, + .func = &cmd_wifi_config, + .argtable = &wifi_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); } void app_console_register_commands(void) { - const esp_console_cmd_t cmds[] = { - { .command = "mode_monitor", .help = "Switch to monitor mode", .func = &cmd_mode_monitor }, - { .command = "mode_sta", .help = "Switch to STA mode", .func = &cmd_mode_sta }, - { .command = "mode_status", .help = "Show device status", .func = &cmd_mode_status }, - { .command = "csi_dump", .help = "Dump collected CSI data", .func = &cmd_csi_dump }, - { .command = "iperf", .help = "Control iperf (start, stop, pps, status)", .func = &cmd_iperf }, - }; - - for (int i = 0; i < sizeof(cmds)/sizeof(cmds[0]); i++) { - ESP_ERROR_CHECK(esp_console_cmd_register(&cmds[i])); - } + register_iperf_cmd(); + register_wifi_cmd(); } diff --git a/components/app_console/app_console.h b/components/app_console/app_console.h index ab0d830..2a92f85 100644 --- a/components/app_console/app_console.h +++ b/components/app_console/app_console.h @@ -5,8 +5,7 @@ extern "C" { #endif /** - * @brief Register all application-specific console commands - * (mode_monitor, mode_sta, mode_status, csi_dump) + * @brief Register application-specific console commands */ void app_console_register_commands(void); diff --git a/components/cmd_transport/CMakeLists.txt b/components/cmd_transport/CMakeLists.txt deleted file mode 100644 index 952fce5..0000000 --- a/components/cmd_transport/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -idf_component_register(SRCS "cmd_transport.c" - INCLUDE_DIRS "." - PRIV_REQUIRES console driver soc esp_driver_usb_serial_jtag) diff --git a/components/cmd_transport/cmd_transport.c b/components/cmd_transport/cmd_transport.c deleted file mode 100644 index 256c63f..0000000 --- a/components/cmd_transport/cmd_transport.c +++ /dev/null @@ -1,138 +0,0 @@ -#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; - } -} - -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; - } -} - -// --- UPDATED DISPATCH LOGIC --- -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) - // Note: The listener (wifi_cfg) is now responsible for sending "OK" if it handles the line. - 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 - if (!handled && strlen(line) > 0) { - int ret; - esp_err_t err = esp_console_run(line, &ret); - - if (err == ESP_ERR_NOT_FOUND) { - // Robustness: Always reply, even for unknown commands - if (reply_func) reply_func("ERROR: Unknown Command\n", reply_ctx); - } else if (err == ESP_OK) { - if (ret == 0) { - // Command Success -> Send ACK so Python knows to proceed - if (reply_func) reply_func("OK\n", reply_ctx); - } else { - // Command logic failed (e.g., iperf returned 1) - char buf[64]; - snprintf(buf, sizeof(buf), "ERROR: Command failed (ret=%d)\n", ret); - if (reply_func) reply_func(buf, reply_ctx); - } - } else { - if (reply_func) reply_func("ERROR: System execution failed\n", reply_ctx); - } - } -} - -// --- 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]; - 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; - xTaskCreatePinnedToCore(uart_listener_task, "cmd_uart", 4096, NULL, 5, NULL, tskNO_AFFINITY); - #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 deleted file mode 100644 index d12db0d..0000000 --- a/components/cmd_transport/cmd_transport.h +++ /dev/null @@ -1,37 +0,0 @@ -#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/wifi_cfg/CMakeLists.txt b/components/wifi_cfg/CMakeLists.txt index b88d65a..5a18d69 100644 --- a/components/wifi_cfg/CMakeLists.txt +++ b/components/wifi_cfg/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "wifi_cfg.c" INCLUDE_DIRS "." - PRIV_REQUIRES nvs_flash esp_wifi esp_netif driver cmd_transport csi_manager) + REQUIRES nvs_flash esp_wifi esp_netif) diff --git a/components/wifi_cfg/wifi_cfg.c b/components/wifi_cfg/wifi_cfg.c index 6b74cd0..bae637c 100644 --- a/components/wifi_cfg/wifi_cfg.c +++ b/components/wifi_cfg/wifi_cfg.c @@ -1,8 +1,6 @@ #include #include #include -#include - #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" @@ -11,149 +9,98 @@ #include "esp_netif.h" #include "esp_wifi.h" #include "esp_event.h" -#include "esp_check.h" - #include "wifi_cfg.h" -#include "cmd_transport.h" -#ifdef CONFIG_ESP_WIFI_CSI_ENABLED -#include "csi_manager.h" -#endif +// Removed unused TAG -static const char *TAG = "wifi_cfg"; static esp_netif_t *sta_netif = NULL; -static bool cfg_dhcp = true; -// --- NVS Helper --- -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); -} - -// --- NVS Save Functions --- - -// 1. Save Network Settings (Namespace: "netcfg") -static void save_net_cfg(const char* ssid, const char* pass, const char* ip, const char* mask, const char* gw, bool dhcp, const char* band, const char* bw, const char* powersave, const char* mode, uint8_t mon_ch){ +// --- Helper: NVS Write --- +static void nvs_write_str(const char *key, const char *val) { nvs_handle_t h; - if (nvs_open("netcfg", NVS_READWRITE, &h) != ESP_OK) return; - - if (ssid) nvs_set_str2(h, "ssid", ssid); - if (pass) nvs_set_str2(h, "pass", pass); - if (ip) nvs_set_str2(h, "ip", ip); - if (mask) nvs_set_str2(h, "mask", mask); - if (gw) nvs_set_str2(h, "gw", gw); - if (band) nvs_set_str2(h, "band", band); - if (bw) nvs_set_str2(h, "bw", bw); - if (powersave) nvs_set_str2(h, "powersave", powersave); - if (mode) nvs_set_str2(h, "mode", mode); - nvs_set_u8(h, "mon_ch", mon_ch); - nvs_set_u8(h, "dhcp", dhcp ? 1 : 0); - - nvs_commit(h); - nvs_close(h); - cfg_dhcp = dhcp; - ESP_LOGI(TAG, "Net Config Saved: SSID=%s IP=%s DHCP=%d", ssid?ssid:"", ip?ip:"", dhcp); + if (nvs_open("netcfg", NVS_READWRITE, &h) == ESP_OK) { + if (val) nvs_set_str(h, key, val); + else nvs_erase_key(h, key); + nvs_commit(h); + nvs_close(h); + } } -// 2. Save Iperf Settings (Namespace: "storage") -> Matches iperf.c keys -static void save_iperf_cfg(const char* dst_ip, const char* role, const char* proto, uint32_t period, uint32_t burst, uint32_t len, uint32_t port, bool enable){ +static void nvs_write_u8(const char *key, uint8_t val) { nvs_handle_t h; - if (nvs_open("storage", NVS_READWRITE, &h) != ESP_OK) return; - - // Note: Keys must match what iperf.c reads (NVS_KEY_IPERF_DST_IP etc) - if (dst_ip && dst_ip[0]) nvs_set_str(h, "iperf_dst_ip", dst_ip); - if (role && role[0]) nvs_set_str(h, "iperf_role", role); - if (proto && proto[0]) nvs_set_str(h, "iperf_proto", proto); - - nvs_set_u32(h, "iperf_period", period); - nvs_set_u32(h, "iperf_burst", burst); - nvs_set_u32(h, "iperf_len", len); - nvs_set_u32(h, "iperf_port", port); - nvs_set_u8(h, "iperf_enabled", enable ? 1 : 0); - - nvs_commit(h); - nvs_close(h); - ESP_LOGI(TAG, "Iperf Config Saved: Target=%s Role=%s Period=%lu", dst_ip?dst_ip:"", role?role:"", (unsigned long)period); + if (nvs_open("netcfg", NVS_READWRITE, &h) == ESP_OK) { + nvs_set_u8(h, key, val); + nvs_commit(h); + nvs_close(h); + } +} + +// --- Public Setters --- + +void wifi_cfg_set_credentials(const char* ssid, const char* pass) { + nvs_write_str("ssid", ssid); + nvs_write_str("pass", pass); +} + +void wifi_cfg_set_static_ip(const char* ip, const char* mask, const char* gw) { + nvs_write_str("ip", ip); + nvs_write_str("mask", mask); + nvs_write_str("gw", gw); +} + +void wifi_cfg_set_dhcp(bool enable) { + nvs_write_u8("dhcp", enable ? 1 : 0); +} + +// --- Init & Load --- + +void wifi_cfg_init(void) { + nvs_flash_init(); } -// --- Load Logic (Network Only - Iperf loads itself) --- static bool load_cfg(char* ssid, size_t ssz, char* pass, size_t psz, char* ip, size_t isz, char* mask, size_t msz, char* gw, size_t gsz, char* band, size_t bsz, char* bw, size_t bwsz, char* powersave, size_t pssz, char* mode, size_t modesz, uint8_t* mon_ch, bool* dhcp){ nvs_handle_t h; if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) return false; + size_t len; - esp_err_t e; - if ((e = nvs_get_str(h, "ssid", NULL, &len)) != ESP_OK){ nvs_close(h); return false; } - if (len >= ssz){ nvs_close(h); return false; } - nvs_get_str(h, "ssid", ssid, &len); - len = psz; e = nvs_get_str(h, "pass", pass, &len); if (e!=ESP_OK) pass[0]=0; - len = isz; e = nvs_get_str(h, "ip", ip, &len); if (e!=ESP_OK) ip[0]=0; - len = msz; e = nvs_get_str(h, "mask", mask, &len); if (e!=ESP_OK) mask[0]=0; - len = gsz; e = nvs_get_str(h, "gw", gw, &len); if (e!=ESP_OK) gw[0]=0; - len = bsz; e = nvs_get_str(h, "band", band, &len); if (e!=ESP_OK) strcpy(band, "2.4G"); - len = bwsz; e = nvs_get_str(h, "bw", bw, &len); if (e!=ESP_OK) strcpy(bw, "HT20"); - len = pssz; e = nvs_get_str(h, "powersave", powersave, &len); if (e!=ESP_OK) strcpy(powersave, "NONE"); - len = modesz; e = nvs_get_str(h, "mode", mode, &len); if (e!=ESP_OK) strcpy(mode, "STA"); + // Load SSID (Mandatory) + len = ssz; + if (nvs_get_str(h, "ssid", ssid, &len) != ESP_OK) { nvs_close(h); return false; } + + // Load Optionals + len = psz; if (nvs_get_str(h, "pass", pass, &len) != ESP_OK) pass[0]=0; + len = isz; if (nvs_get_str(h, "ip", ip, &len) != ESP_OK) ip[0]=0; + len = msz; if (nvs_get_str(h, "mask", mask, &len) != ESP_OK) mask[0]=0; + len = gsz; if (nvs_get_str(h, "gw", gw, &len) != ESP_OK) gw[0]=0; + + // Defaults + len = bsz; if (nvs_get_str(h, "band", band, &len) != ESP_OK) strcpy(band, "2.4G"); + len = bwsz; if (nvs_get_str(h, "bw", bw, &len) != ESP_OK) strcpy(bw, "HT20"); + len = pssz; if (nvs_get_str(h, "powersave", powersave, &len) != ESP_OK) strcpy(powersave, "NONE"); + len = modesz; 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; uint8_t d=1; nvs_get_u8(h, "dhcp", &d); *dhcp = (d!=0); + nvs_close(h); return true; } -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) { - strcpy(mode, "STA"); *mon_ch = 36; return false; - } - size_t len = 16; - 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); - return true; -} - -static atomic_bool s_net_stack_ready = false; -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"); - esp_err_t err = esp_event_loop_create_default(); - if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { - ESP_RETURN_ON_ERROR(err, TAG, "event loop create"); - } - } - return ESP_OK; -} - -static atomic_bool s_wifi_inited = false; -esp_err_t wifi_ensure_inited(void) { - bool expected = false; - 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) { - atomic_store(&s_wifi_inited, false); - ESP_RETURN_ON_ERROR(err, TAG, "esp_wifi_init"); - } - return ESP_OK; -} - static void apply_ip_static(const char* ip, const char* mask, const char* gw){ if (!sta_netif) return; - if (!ip || !ip[0] || !mask || !mask[0] || !gw || !gw[0]) return; + if (!ip || !ip[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_ERROR_CHECK( esp_netif_set_ip_info(sta_netif, &info) ); + info.netmask.addr = (mask && mask[0]) ? esp_ip4addr_aton(mask) : esp_ip4addr_aton("255.255.255.0"); + info.gw.addr = (gw && gw[0]) ? esp_ip4addr_aton(gw) : 0; + + esp_netif_set_ip_info(sta_netif, &info); } bool wifi_cfg_apply_from_nvs(void) { @@ -165,16 +112,11 @@ bool wifi_cfg_apply_from_nvs(void) { band,sizeof(band), bw,sizeof(bw), powersave,sizeof(powersave), mode,sizeof(mode), &mon_ch, &dhcp)){ return false; } - if (ssid[0] == '\0') return false; - static bool inited = false; - if (!inited){ - nvs_flash_init(); - ensure_net_stack_once(); - if (sta_netif == NULL) sta_netif = esp_netif_create_default_wifi_sta(); - wifi_ensure_inited(); - inited = true; - } + if (sta_netif == NULL) sta_netif = esp_netif_create_default_wifi_sta(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + esp_wifi_init(&cfg); wifi_config_t wcfg = {0}; strlcpy((char*)wcfg.sta.ssid, ssid, sizeof(wcfg.sta.ssid)); @@ -183,200 +125,32 @@ bool wifi_cfg_apply_from_nvs(void) { wcfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH; wcfg.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; - if (strcmp(band, "5G") == 0) wcfg.sta.channel = 0; - else wcfg.sta.channel = 0; - esp_wifi_set_mode(WIFI_MODE_STA); - - #if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 - wifi_protocols_t protocols = { - .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_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 - 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 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 + else esp_netif_dhcpc_start(sta_netif); esp_wifi_start(); - - 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_wifi_connect(); return true; } -// --- Parsing State --- -typedef struct { - // Network - char ssid[64]; - char pass[64]; - char ip[32]; - char mask[32]; - char gw[32]; - char band[16]; - char bw[16]; - char powersave[16]; - char mode[16]; - uint8_t mon_ch; - bool dhcp; - bool csi_enable; - - // Iperf - char iperf_dest[32]; - char iperf_role[16]; - char iperf_proto[8]; - uint32_t iperf_period_us; - uint32_t iperf_burst; - uint32_t iperf_len; - uint32_t iperf_port; - bool iperf_enable; -} cfg_state_t; - -static void on_cfg_line(const char *line, cfg_state_t *s){ - // Network Parsing - if (strncmp(line, "SSID:",5)==0){ strncpy(s->ssid, line+5, 63); s->ssid[63]=0; return; } - if (strncmp(line, "PASS:",5)==0){ strncpy(s->pass, line+5, 63); s->pass[63]=0; return; } - if (strncmp(line, "IP:",3)==0){ strncpy(s->ip, line+3, 31); s->ip[31]=0; return; } - if (strncmp(line, "MASK:",5)==0){ strncpy(s->mask, line+5, 31); s->mask[31]=0; return; } - if (strncmp(line, "GW:",3)==0){ strncpy(s->gw, line+3, 31); s->gw[31]=0; return; } - if (strncmp(line, "BAND:",5)==0){ strncpy(s->band, line+5, 15); s->band[15]=0; return; } - if (strncmp(line, "BW:",3)==0){ strncpy(s->bw, line+3, 15); s->bw[15]=0; return; } - if (strncmp(line, "POWERSAVE:",10)==0){ strncpy(s->powersave, line+10, 15); s->powersave[15]=0; return; } - if (strncmp(line, "MODE:",5)==0){ strncpy(s->mode, line+5, 15); s->mode[15]=0; return; } - if (strncmp(line, "MON_CH:",7)==0){ s->mon_ch = atoi(line+7); return; } - if (strncmp(line, "DHCP:",5)==0){ s->dhcp = atoi(line+5) ? true:false; return; } - - // Iperf Parsing (Matches Python Script Keys) - // Support both DEST and DST to be safe - if (strncmp(line, "IPERF_DEST_IP:", 14) == 0) { strncpy(s->iperf_dest, line+14, 31); s->iperf_dest[31]=0; return; } - if (strncmp(line, "IPERF_DST_IP:", 13) == 0) { strncpy(s->iperf_dest, line+13, 31); s->iperf_dest[31]=0; return; } - - if (strncmp(line, "IPERF_ROLE:", 11) == 0) { strncpy(s->iperf_role, line+11, 15); s->iperf_role[15]=0; return; } - if (strncmp(line, "IPERF_PROTO:", 12) == 0) { strncpy(s->iperf_proto, line+12, 7); s->iperf_proto[7]=0; return; } - - if (strncmp(line, "IPERF_PERIOD_US:", 16) == 0) { s->iperf_period_us = atoi(line+16); return; } - if (strncmp(line, "IPERF_BURST:", 12) == 0) { s->iperf_burst = atoi(line+12); return; } - if (strncmp(line, "IPERF_LEN:", 10) == 0) { s->iperf_len = atoi(line+10); return; } - if (strncmp(line, "IPERF_PORT:", 11) == 0) { s->iperf_port = atoi(line+11); return; } - if (strncmp(line, "IPERF_ENABLED:", 14) == 0) { s->iperf_enable = atoi(line+14) ? true:false; return; } - -#ifdef CONFIG_ESP_WIFI_CSI_ENABLED - if (strncmp(line, "CSI:",4)==0){ s->csi_enable = atoi(line+4) ? true:false; return; } -#endif -} - -static bool wifi_cfg_cmd_handler(const char *line, cmd_reply_func_t reply_func, void *reply_ctx) { - static bool in_cfg = false; - static cfg_state_t s; - - if (!in_cfg) { - if (strcmp(line, "CFG") == 0) { - in_cfg = true; - // Clear all buffers - memset(&s, 0, sizeof(s)); - // Set Defaults - s.mon_ch = 36; - s.dhcp = true; - s.csi_enable = false; - s.iperf_period_us = 10000; - s.iperf_burst = 1; - s.iperf_len = 1470; - s.iperf_port = 5001; - s.iperf_enable = true; - strcpy(s.iperf_dest, "192.168.1.50"); - strcpy(s.iperf_role, "CLIENT"); - strcpy(s.iperf_proto, "UDP"); - - // --- NEW: ACK Start of CFG --- - if (reply_func) reply_func("OK\n", reply_ctx); - return true; - } - return false; - } - - if (strcmp(line, "END") == 0) { - // Apply Network Defaults if missing - if (!s.band[0]) strcpy(s.band, "2.4G"); - if (!s.bw[0]) strcpy(s.bw, "HT20"); - if (!s.powersave[0]) strcpy(s.powersave, "NONE"); - if (!s.mode[0]) strcpy(s.mode, "STA"); - - // 1. Save Network - save_net_cfg(s.ssid, s.pass, s.ip, s.mask, s.gw, s.dhcp, s.band, s.bw, s.powersave, s.mode, s.mon_ch); - - // 2. Save Iperf - save_iperf_cfg(s.iperf_dest, s.iperf_role, s.iperf_proto, s.iperf_period_us, s.iperf_burst, s.iperf_len, s.iperf_port, s.iperf_enable); - - // 3. Save CSI -#ifdef CONFIG_ESP_WIFI_CSI_ENABLED - csi_mgr_save_enable_state(s.csi_enable); -#endif - - // --- NEW: ACK End of CFG --- - if (reply_func) reply_func("OK Config Saved\n", reply_ctx); - - // Apply changes immediately - wifi_cfg_apply_from_nvs(); - - in_cfg = false; - return true; - } - - on_cfg_line(line, &s); - - // --- NEW: ACK Intermediate Line --- - if (reply_func) reply_func("OK\n", reply_ctx); - - return true; -} - -void wifi_cfg_init(void){ - nvs_flash_init(); - cmd_transport_init(); - cmd_transport_register_listener(wifi_cfg_cmd_handler); -} - wifi_ps_type_t wifi_cfg_get_power_save_mode(void) { - char powersave[16] = {0}; - nvs_handle_t h; - if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) return WIFI_PS_NONE; - size_t len = sizeof(powersave); - nvs_get_str(h, "powersave", powersave, &len); - nvs_close(h); - - if (strcmp(powersave, "MIN") == 0) return WIFI_PS_MIN_MODEM; - if (strcmp(powersave, "MAX") == 0) return WIFI_PS_MAX_MODEM; return WIFI_PS_NONE; } bool wifi_cfg_get_bandwidth(char *buf, size_t buf_size) { - if (!buf || buf_size < 1) return false; - nvs_handle_t h; - if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) { - strncpy(buf, "Unknown", buf_size); return false; - } - size_t len = buf_size; - esp_err_t err = nvs_get_str(h, "bw", buf, &len); - nvs_close(h); - return (err == ESP_OK); + if (buf) strncpy(buf, "HT20", buf_size); + return true; +} + +bool wifi_cfg_get_mode(char *mode, uint8_t *mon_ch) { + nvs_handle_t h; + if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) return false; + size_t len = 16; + if (nvs_get_str(h, "mode", mode, &len) != ESP_OK) strcpy(mode, "STA"); + nvs_get_u8(h, "mon_ch", mon_ch); + nvs_close(h); + return true; } diff --git a/components/wifi_cfg/wifi_cfg.h b/components/wifi_cfg/wifi_cfg.h index 6bc4f35..c02a6dc 100644 --- a/components/wifi_cfg/wifi_cfg.h +++ b/components/wifi_cfg/wifi_cfg.h @@ -8,59 +8,19 @@ extern "C" { #endif -/** - * @brief Initialize the WiFi configuration system - * - * Spawns listener tasks for both UART and USB-Serial/JTAG interfaces - * to receive configuration commands. - */ +// --- Initialization --- void wifi_cfg_init(void); -/** - * @brief Apply WiFi configuration from NVS - * - * @return true if configuration was found and applied, false otherwise - */ +// --- Getters (Used by Controller) --- bool wifi_cfg_apply_from_nvs(void); - -/** - * @brief Force DHCP mode enable/disable - * - * @param enable true to enable DHCP, false to disable - */ -void wifi_cfg_force_dhcp(bool enable); - -/** - * @brief Get the configured power save mode from NVS - * - * @return wifi_ps_type_t Power save mode (WIFI_PS_NONE, WIFI_PS_MIN_MODEM, or WIFI_PS_MAX_MODEM) - */ wifi_ps_type_t wifi_cfg_get_power_save_mode(void); - -/** - * @brief Get the configured bandwidth from NVS - * - * @param buf Buffer to store bandwidth string (e.g., "HT20", "HT40", "VHT80") - * @param buf_size Size of buffer - * @return true if bandwidth was retrieved, false otherwise - */ bool wifi_cfg_get_bandwidth(char *buf, size_t buf_size); - -/** - * @brief Get operating mode and monitor channel from NVS - * - * @param mode Output buffer for mode string (min 16 bytes) - * @param mon_ch Output pointer for monitor channel - * @return true if mode retrieved, false if no config in NVS - */ bool wifi_cfg_get_mode(char *mode, uint8_t *mon_ch); -/** - * @brief Ensure WiFi driver is initialized (thread-safe, idempotent) - * - * @return ESP_OK on success, error code otherwise - */ -esp_err_t wifi_ensure_inited(void); +// --- Setters (Used by Console) --- +void wifi_cfg_set_credentials(const char* ssid, const char* pass); +void wifi_cfg_set_static_ip(const char* ip, const char* mask, const char* gw); +void wifi_cfg_set_dhcp(bool enable); #ifdef __cplusplus } diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 530c5cf..b69510f 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,23 +1,3 @@ -idf_component_register( - SRCS "main.c" - INCLUDE_DIRS "." - PRIV_REQUIRES - nvs_flash - esp_wifi - esp_netif - esp_event - lwip - console - driver # <--- Added (For GPIO definitions) - cmd_transport # <--- Added (For cmd_transport.h) - iperf - wifi_cfg - csi_log - wifi_monitor - gps_sync - led_strip - status_led - csi_manager - wifi_controller - app_console -) +idf_component_register(SRCS "main.c" + INCLUDE_DIRS "." + PRIV_REQUIRES nvs_flash esp_netif wifi_controller wifi_cfg app_console iperf status_led gps_sync console) diff --git a/main/board_config.h b/main/board_config.h index 3ad8377..e4f4124 100644 --- a/main/board_config.h +++ b/main/board_config.h @@ -1,37 +1,45 @@ -#pragma once -#include "driver/gpio.h" +#ifndef BOARD_CONFIG_H +#define BOARD_CONFIG_H -// --- Hardware Configuration --- +#include "sdkconfig.h" -#if defined(CONFIG_IDF_TARGET_ESP32S3) - // ESP32-S3 - #define RGB_LED_GPIO 48 - #define HAS_RGB_LED 1 - #define GPS_TX_PIN GPIO_NUM_5 - #define GPS_RX_PIN GPIO_NUM_4 - #define GPS_PPS_PIN GPIO_NUM_6 - -#elif defined(CONFIG_IDF_TARGET_ESP32C5) - // ESP32-C5 - #define RGB_LED_GPIO 27 - #define HAS_RGB_LED 1 - #define GPS_TX_PIN GPIO_NUM_24 - #define GPS_RX_PIN GPIO_NUM_23 - #define GPS_PPS_PIN GPIO_NUM_25 - -#elif defined(CONFIG_IDF_TARGET_ESP32) - // ESP32 (Original) - #define RGB_LED_GPIO 2 // Standard Blue LED - #define HAS_RGB_LED 0 // Not RGB - #define GPS_TX_PIN GPIO_NUM_17 - #define GPS_RX_PIN GPIO_NUM_16 - #define GPS_PPS_PIN GPIO_NUM_4 - -#else - // Fallback - #define RGB_LED_GPIO 8 - #define HAS_RGB_LED 1 - #define GPS_TX_PIN GPIO_NUM_1 - #define GPS_RX_PIN GPIO_NUM_3 - #define GPS_PPS_PIN GPIO_NUM_5 +// ============================================================================ +// ESP32-C5 (DevKitC-1) +// ============================================================================ +#ifdef CONFIG_IDF_TARGET_ESP32C5 + #define RGB_LED_GPIO 8 // Common addressable LED pin for C5 + #define HAS_RGB_LED 1 #endif + +// ============================================================================ +// ESP32-S3 (DevKitC-1) +// ============================================================================ +#ifdef CONFIG_IDF_TARGET_ESP32S3 + // Most S3 DevKits use GPIO 48 for the addressable RGB LED. + // If yours uses GPIO 38, change this value. + #define RGB_LED_GPIO 48 + #define HAS_RGB_LED 1 +#endif + +// ============================================================================ +// ESP32 (Original / Standard) +// ============================================================================ +#ifdef CONFIG_IDF_TARGET_ESP32 + // Standard ESP32 DevKits usually have a single blue LED on GPIO 2. + // They rarely have an addressable RGB LED built-in. + #define RGB_LED_GPIO 2 + #define HAS_RGB_LED 0 +#endif + +// ============================================================================ +// Fallbacks (Prevent Compilation Errors) +// ============================================================================ +#ifndef RGB_LED_GPIO + #define RGB_LED_GPIO 2 +#endif + +#ifndef HAS_RGB_LED + #define HAS_RGB_LED 0 +#endif + +#endif // BOARD_CONFIG_H diff --git a/main/main.c b/main/main.c index 25d51ae..9e72b2e 100644 --- a/main/main.c +++ b/main/main.c @@ -1,161 +1,110 @@ #include #include - +#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" -#include "esp_event.h" #include "esp_log.h" #include "esp_console.h" +#include "esp_vfs_dev.h" +#include "driver/uart.h" #include "nvs_flash.h" #include "esp_netif.h" -#include "lwip/inet.h" +#include "esp_event.h" // Components -#include "board_config.h" #include "status_led.h" -#include "gps_sync.h" -#include "wifi_cfg.h" +#include "board_config.h" #include "wifi_controller.h" +#include "wifi_cfg.h" #include "app_console.h" -#include "iperf.h" -// GUARDED INCLUDE #ifdef CONFIG_ESP_WIFI_CSI_ENABLED #include "csi_log.h" #include "csi_manager.h" #endif -// --- VERSION DEFINITION --- -#define APP_VERSION "1.1.0" +#define APP_VERSION "2.0.0-SHELL" static const char *TAG = "MAIN"; -// --- Version Command ----------------------------------------------- -static int cmd_version(int argc, char **argv) { - printf("APP_VERSION: %s\n", APP_VERSION); +// --- System Commands --- + +static int cmd_restart(int argc, char **argv) { + ESP_LOGI(TAG, "Restarting..."); + esp_restart(); return 0; } -// --- 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) { - if (event_id == WIFI_EVENT_STA_START) { - if (wifi_ctl_get_mode() == WIFI_CTL_MODE_STA) { - status_led_set_state(LED_STATE_WAITING); - } - } - else if (event_id == WIFI_EVENT_STA_DISCONNECTED) { - if (wifi_ctl_get_mode() == WIFI_CTL_MODE_STA) { - status_led_set_state(LED_STATE_FAILED); - } - } - } - else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - if (wifi_ctl_get_mode() != WIFI_CTL_MODE_STA) return; - - ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; - ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip)); - - status_led_set_state(LED_STATE_CONNECTED); - -#ifdef CONFIG_ESP_WIFI_CSI_ENABLED - if (csi_mgr_should_enable()) { - ESP_LOGI(TAG, "CSI enabled in config - starting capture"); - csi_mgr_enable_async(); - csi_mgr_schedule_dump(); - } else { - ESP_LOGI(TAG, "CSI disabled in config - skipping capture"); - } -#endif - - // iperf_start() will fill this from NVS (including Dest IP and Role) - iperf_cfg_t cfg = { 0 }; - iperf_start(&cfg); - } +static int cmd_version(int argc, char **argv) { + printf("APP_VERSION: %s\n", APP_VERSION); + printf("IDF_VERSION: %s\n", esp_get_idf_version()); + return 0; } -// --- Main ---------------------------------------------------------- +static void register_system_common(void) { + const esp_console_cmd_t restart_cmd = { + .command = "reset", + .help = "Software reset of the device", + .func = &cmd_restart + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&restart_cmd)); + + const esp_console_cmd_t version_cmd = { + .command = "version", + .help = "Get firmware version", + .func = &cmd_version + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&version_cmd)); +} + +// --- Main Application --- + void app_main(void) { - // 1. System Init + // 1. 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); + + // 2. Initialize Netif & Event Loop ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); - // 2. Hardware/Driver Init + // 3. Hardware Init + status_led_init(RGB_LED_GPIO, HAS_RGB_LED); #ifdef CONFIG_ESP_WIFI_CSI_ENABLED ESP_ERROR_CHECK(csi_log_init()); -#endif - status_led_init(RGB_LED_GPIO, HAS_RGB_LED); - - 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, - }; - gps_sync_init(&gps_cfg, true); - - // 3. Subsystem Init -#ifdef CONFIG_ESP_WIFI_CSI_ENABLED csi_mgr_init(); #endif + + // 4. Initialize WiFi Controller (Loads config from NVS automatically) wifi_ctl_init(); - wifi_cfg_init(); - // 4. Console Registry Init - esp_console_config_t console_config = { - .max_cmdline_args = 8, - .max_cmdline_length = 256, - }; - ESP_ERROR_CHECK(esp_console_init(&console_config)); - esp_console_register_help_command(); + // 5. Initialize Console + esp_console_repl_t *repl = NULL; + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); - // Register App Commands + // This prompt is the anchor for your Python script + repl_config.prompt = "esp32> "; + repl_config.max_cmdline_length = 1024; + + // Install UART driver for Console (Standard IO) + esp_console_dev_uart_config_t hw_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl)); + + // 6. Register Commands + register_system_common(); app_console_register_commands(); - // Register Version Command (Built-in) - const esp_console_cmd_t version_cmd_def = { - .command = "version", - .help = "Get firmware version", - .hint = NULL, - .func = &cmd_version, - }; - ESP_ERROR_CHECK(esp_console_cmd_register(&version_cmd_def)); + // 7. Start Shell + printf("\n ==================================================\n"); + printf(" | ESP32 iPerf Shell - Ready |\n"); + printf(" | Type 'help' for commands |\n"); + printf(" ==================================================\n"); - // 5. 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. Application Start -#ifdef CONFIG_ESP_WIFI_CSI_ENABLED - bool csi_enabled = csi_mgr_should_enable(); - ESP_LOGI(TAG, "CSI Capture: %s", csi_enabled ? "ENABLED" : "DISABLED"); -#endif - - if (wifi_cfg_apply_from_nvs()) { - status_led_set_state(LED_STATE_WAITING); - - char mode[16] = {0}; - uint8_t mon_ch = 36; - if (wifi_cfg_get_mode(mode, &mon_ch) && strcmp(mode, "MONITOR") == 0) { - wifi_ctl_auto_monitor_start(mon_ch); - } - } else { - status_led_set_state(LED_STATE_NO_CONFIG); - ESP_LOGW(TAG, "No Config Found. Waiting for setup..."); - } - - // 7. Keep Main Task Alive - ESP_LOGI(TAG, "Initialization complete. Entering idle loop."); - ESP_LOGI(TAG, "Firmware Version: %s", APP_VERSION); // Log version on boot - - while (true) { - vTaskDelay(pdMS_TO_TICKS(1000)); - } + // This function runs the REPL loop and does not return + ESP_ERROR_CHECK(esp_console_start_repl(repl)); }