From 251d936f35240ea5fa1de27400147437619d3922 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 8 Dec 2025 17:18:46 -0800 Subject: [PATCH] refactore component wifi_controller --- components/wifi_controller/CMakeLists.txt | 4 + components/wifi_controller/wifi_controller.c | 206 +++++++++++++++++++ components/wifi_controller/wifi_controller.h | 57 +++++ main/CMakeLists.txt | 1 + main/main.c | 168 ++------------- 5 files changed, 288 insertions(+), 148 deletions(-) create mode 100644 components/wifi_controller/CMakeLists.txt create mode 100644 components/wifi_controller/wifi_controller.c create mode 100644 components/wifi_controller/wifi_controller.h diff --git a/components/wifi_controller/CMakeLists.txt b/components/wifi_controller/CMakeLists.txt new file mode 100644 index 0000000..301494d --- /dev/null +++ b/components/wifi_controller/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "wifi_controller.c" + INCLUDE_DIRS "." + REQUIRES esp_wifi freertos + PRIV_REQUIRES csi_manager iperf status_led wifi_monitor gps_sync log esp_netif) diff --git a/components/wifi_controller/wifi_controller.c b/components/wifi_controller/wifi_controller.c new file mode 100644 index 0000000..0b261af --- /dev/null +++ b/components/wifi_controller/wifi_controller.c @@ -0,0 +1,206 @@ +#include "wifi_controller.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_wifi.h" +#include "inttypes.h" + +// Dependencies +#include "iperf.h" +#include "csi_manager.h" +#include "status_led.h" +#include "wifi_monitor.h" +#include "gps_sync.h" + +static const char *TAG = "WIFI_CTL"; + +static wifi_ctl_mode_t s_current_mode = WIFI_CTL_MODE_STA; +static uint8_t s_monitor_channel = 6; +static bool s_monitor_enabled = false; +static uint32_t s_monitor_frame_count = 0; +static TaskHandle_t s_monitor_stats_task_handle = NULL; + +// --- Helper: Log Collapse Events --- +static void log_collapse_event(float nav_duration_us, int rssi, int retry) { + gps_timestamp_t ts = gps_get_timestamp(); + // CSV Format: COLLAPSE,MonoMS,GpsMS,Synced,Duration,RSSI,Retry + printf("COLLAPSE,%" PRIi64 ",%" PRIi64 ",%d,%.2f,%d,%d\n", + ts.monotonic_ms, + ts.gps_ms, + ts.synced ? 1 : 0, + nav_duration_us, + rssi, + retry); +} + +// --- Monitor Callbacks & Tasks --- + +static void monitor_frame_callback(const wifi_frame_info_t *frame, const uint8_t *payload, uint16_t len) { + s_monitor_frame_count++; + + // Check for Collapse conditions (High NAV + Retry) + if (frame->retry && frame->duration_id > 5000) { + log_collapse_event((float)frame->duration_id, frame->rssi, frame->retry); + } + + if (frame->duration_id > 30000) { + ESP_LOGW("MONITOR", "⚠️ VERY HIGH NAV: %u us", frame->duration_id); + } +} + +static void monitor_stats_task(void *arg) { + while (1) { + vTaskDelay(pdMS_TO_TICKS(10000)); + wifi_collapse_stats_t stats; + if (wifi_monitor_get_stats(&stats) == ESP_OK) { + ESP_LOGI("MONITOR", "--- Stats: %lu frames, Retry: %.2f%%, Avg NAV: %u us ---", + (unsigned long)stats.total_frames, stats.retry_rate, stats.avg_nav); + + if (wifi_monitor_is_collapsed()) { + ESP_LOGW("MONITOR", "⚠️ ⚠️ COLLAPSE DETECTED! ⚠️ ⚠️"); + } + } + } +} + +static void auto_monitor_task_func(void *arg) { + uint8_t channel = (uint8_t)(uintptr_t)arg; + + ESP_LOGI(TAG, "Waiting for WiFi connection before switching to monitor mode..."); + // Wait until LED indicates connected + while (status_led_get_state() != LED_STATE_CONNECTED) { + vTaskDelay(pdMS_TO_TICKS(500)); + } + + ESP_LOGI(TAG, "WiFi connected, waiting for GPS sync (2s)..."); + vTaskDelay(pdMS_TO_TICKS(2000)); + + ESP_LOGI(TAG, "Auto-switching to MONITOR mode on channel %d...", channel); + wifi_ctl_switch_to_monitor(channel, WIFI_BW_HT20); + vTaskDelete(NULL); +} + +// --- API Implementation --- + +void wifi_ctl_init(void) { + s_current_mode = WIFI_CTL_MODE_STA; + s_monitor_enabled = false; + s_monitor_frame_count = 0; +} + +esp_err_t wifi_ctl_switch_to_monitor(uint8_t channel, wifi_bandwidth_t bandwidth) { + if (s_current_mode == WIFI_CTL_MODE_MONITOR) { + ESP_LOGW(TAG, "Already in monitor mode"); + return ESP_OK; + } + + // Monitor mode typically requires 20MHz + if (bandwidth != WIFI_BW_HT20) { + ESP_LOGW(TAG, "Forcing bandwidth to 20MHz for monitor mode"); + bandwidth = WIFI_BW_HT20; + } + + ESP_LOGI(TAG, "Switching to MONITOR MODE (Ch %d)", channel); + + // 1. Stop high-level apps + iperf_stop(); + vTaskDelay(pdMS_TO_TICKS(500)); + + // 2. Disable CSI (hardware conflict) + csi_mgr_disable(); + + // 3. Teardown Station + esp_wifi_disconnect(); + esp_wifi_stop(); + vTaskDelay(pdMS_TO_TICKS(500)); + + // 4. Re-init in NULL/Promiscuous Mode + esp_wifi_set_mode(WIFI_MODE_NULL); + + if (wifi_monitor_init(channel, monitor_frame_callback) != ESP_OK) { + ESP_LOGE(TAG, "Failed to init monitor mode"); + return ESP_FAIL; + } + + esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth); + + if (wifi_monitor_start() != ESP_OK) { + ESP_LOGE(TAG, "Failed to start monitor mode"); + return ESP_FAIL; + } + + // 5. Update State + s_monitor_enabled = true; + s_current_mode = WIFI_CTL_MODE_MONITOR; + s_monitor_channel = channel; + status_led_set_state(LED_STATE_MONITORING); + + if (s_monitor_stats_task_handle == NULL) { + xTaskCreate(monitor_stats_task, "monitor_stats", 4096, NULL, 5, &s_monitor_stats_task_handle); + } + + return ESP_OK; +} + +esp_err_t wifi_ctl_switch_to_sta(wifi_band_mode_t band_mode) { + if (s_current_mode == WIFI_CTL_MODE_STA) { + ESP_LOGW(TAG, "Already in STA mode"); + return ESP_OK; + } + + ESP_LOGI(TAG, "Switching to STA MODE"); + + // 1. Stop Monitor Tasks + if (s_monitor_stats_task_handle != NULL) { + vTaskDelete(s_monitor_stats_task_handle); + s_monitor_stats_task_handle = NULL; + } + + // 2. Stop Monitor Driver + if (s_monitor_enabled) { + wifi_monitor_stop(); + s_monitor_enabled = false; + vTaskDelay(pdMS_TO_TICKS(500)); + } + + // 3. Re-enable Station Mode + esp_wifi_set_mode(WIFI_MODE_STA); + vTaskDelay(pdMS_TO_TICKS(500)); + + // 4. Configure & Connect + wifi_config_t wifi_config; + esp_wifi_get_config(WIFI_IF_STA, &wifi_config); + wifi_config.sta.channel = 0; // Auto channel scan + + // Note: band_mode preference logic would go here if using scan filters + + esp_wifi_set_config(WIFI_IF_STA, &wifi_config); + esp_wifi_start(); + vTaskDelay(pdMS_TO_TICKS(500)); + esp_wifi_connect(); + + // 5. Update State + s_current_mode = WIFI_CTL_MODE_STA; + status_led_set_state(LED_STATE_WAITING); + + // Note: csi_mgr_enable is handled by GOT_IP event in main.c + + return ESP_OK; +} + +void wifi_ctl_auto_monitor_start(uint8_t channel) { + // Pass channel as value-in-pointer (it fits in void*) + xTaskCreate(auto_monitor_task_func, "auto_monitor", 4096, (void*)(uintptr_t)channel, 5, NULL); +} + +wifi_ctl_mode_t wifi_ctl_get_mode(void) { + return s_current_mode; +} + +uint8_t wifi_ctl_get_monitor_channel(void) { + return s_monitor_channel; +} + +uint32_t wifi_ctl_get_monitor_frame_count(void) { + return s_monitor_frame_count; +} diff --git a/components/wifi_controller/wifi_controller.h b/components/wifi_controller/wifi_controller.h new file mode 100644 index 0000000..5346cbf --- /dev/null +++ b/components/wifi_controller/wifi_controller.h @@ -0,0 +1,57 @@ +#pragma once + +#include "esp_err.h" +#include "esp_wifi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + WIFI_CTL_MODE_STA, + WIFI_CTL_MODE_MONITOR +} wifi_ctl_mode_t; + +/** + * @brief Initialize the WiFi Controller + */ +void wifi_ctl_init(void); + +/** + * @brief Switch operation mode to Monitor (Sniffer) + * @param channel WiFi channel (1-165) + * @param bandwidth Bandwidth (usually WIFI_BW_HT20 for monitor) + */ +esp_err_t wifi_ctl_switch_to_monitor(uint8_t channel, wifi_bandwidth_t bandwidth); + +/** + * @brief Switch operation mode to Station (Client) + * @param band_mode Band preference (Auto, 2G only, 5G only) + */ +esp_err_t wifi_ctl_switch_to_sta(wifi_band_mode_t band_mode); + +/** + * @brief Start the auto-monitor task + * Waits for connection, waits for GPS, then switches to monitor mode. + * @param channel Channel to monitor + */ +void wifi_ctl_auto_monitor_start(uint8_t channel); + +/** + * @brief Get current operation mode + */ +wifi_ctl_mode_t wifi_ctl_get_mode(void); + +/** + * @brief Get the current monitor channel + */ +uint8_t wifi_ctl_get_monitor_channel(void); + +/** + * @brief Get total frames captured in monitor mode + */ +uint32_t wifi_ctl_get_monitor_frame_count(void); + +#ifdef __cplusplus +} +#endif diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 51ce27d..cfc379a 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -18,4 +18,5 @@ idf_component_register( led_strip status_led csi_manager + wifi_controller ) diff --git a/main/main.c b/main/main.c index 3e28d1e..b133c68 100644 --- a/main/main.c +++ b/main/main.c @@ -8,7 +8,6 @@ #include "esp_system.h" #include "esp_event.h" #include "esp_log.h" -#include "esp_wifi.h" #include "esp_console.h" #include "linenoise/linenoise.h" #include "nvs_flash.h" @@ -19,135 +18,21 @@ #include "iperf.h" #include "wifi_cfg.h" #include "csi_log.h" -#include "wifi_monitor.h" #include "gps_sync.h" #include "status_led.h" #include "board_config.h" -#include "csi_manager.h" // <--- New Component +#include "csi_manager.h" +#include "wifi_controller.h" // <--- New Component static const char *TAG = "MAIN"; -// --- WiFi Operation Mode --- -typedef enum { - WIFI_MODE_STA_CSI, - WIFI_MODE_MONITOR -} wifi_operation_mode_t; - -static wifi_operation_mode_t current_wifi_mode = WIFI_MODE_STA_CSI; -static uint8_t monitor_channel = 6; -static bool wifi_connected = false; -static bool has_config = false; - -// --- Forward Declarations --- -static void auto_monitor_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(); - printf("COLLAPSE,%" PRIi64 ",%" PRIi64 ",%d,%.2f,%d,%d\n", - ts.monotonic_ms, ts.gps_ms, ts.synced ? 1 : 0, nav_duration_us, rssi, retry); -} - -// --- WiFi Monitor Mode Support ------------------------------------- -static bool s_monitor_enabled = false; -static TaskHandle_t s_monitor_stats_task_handle = NULL; - -static void monitor_frame_callback(const wifi_frame_info_t *frame, const uint8_t *payload, uint16_t len) { - if (frame->retry && frame->duration_id > 5000) { - log_collapse_event((float)frame->duration_id, frame->rssi, frame->retry); - } - if (frame->duration_id > 30000) { - ESP_LOGW("MONITOR", "⚠️ VERY HIGH NAV: %u us", frame->duration_id); - } -} - -static void monitor_stats_task(void *arg) { - while (1) { - vTaskDelay(pdMS_TO_TICKS(10000)); - wifi_collapse_stats_t stats; - if (wifi_monitor_get_stats(&stats) == ESP_OK) { - ESP_LOGI("MONITOR", "--- Stats: %lu frames, Retry: %.2f%%, Avg NAV: %u us ---", - (unsigned long)stats.total_frames, stats.retry_rate, stats.avg_nav); - if (wifi_monitor_is_collapsed()) { - ESP_LOGW("MONITOR", "⚠️ ⚠️ COLLAPSE DETECTED! ⚠️ ⚠️"); - } - } - } -} - -// --- Mode Switching Functions -------------------------------------- - -esp_err_t switch_to_monitor_mode(uint8_t channel, wifi_bandwidth_t bandwidth) { - if (current_wifi_mode == WIFI_MODE_MONITOR) return ESP_OK; - - if (bandwidth != WIFI_BW_HT20) bandwidth = WIFI_BW_HT20; - - ESP_LOGI(TAG, "Switching to MONITOR MODE (Ch %d)", channel); - iperf_stop(); - vTaskDelay(pdMS_TO_TICKS(500)); - - // Disable CSI using Manager - csi_mgr_disable(); - - esp_wifi_disconnect(); - esp_wifi_stop(); - vTaskDelay(pdMS_TO_TICKS(500)); - esp_wifi_set_mode(WIFI_MODE_NULL); - - if (wifi_monitor_init(channel, monitor_frame_callback) != ESP_OK) return ESP_FAIL; - esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth); - if (wifi_monitor_start() != ESP_OK) return ESP_FAIL; - - s_monitor_enabled = true; - current_wifi_mode = WIFI_MODE_MONITOR; - status_led_set_state(LED_STATE_MONITORING); - monitor_channel = channel; - - if (s_monitor_stats_task_handle == NULL) { - xTaskCreate(monitor_stats_task, "monitor_stats", 4096, NULL, 5, &s_monitor_stats_task_handle); - } - return ESP_OK; -} - -esp_err_t switch_to_sta_mode(wifi_band_mode_t band_mode) { - if (current_wifi_mode == WIFI_MODE_STA_CSI) return ESP_OK; - - ESP_LOGI(TAG, "Switching to STA MODE"); - - if (s_monitor_stats_task_handle != NULL) { - vTaskDelete(s_monitor_stats_task_handle); - s_monitor_stats_task_handle = NULL; - } - if (s_monitor_enabled) { - wifi_monitor_stop(); - s_monitor_enabled = false; - vTaskDelay(pdMS_TO_TICKS(500)); - } - - esp_wifi_set_mode(WIFI_MODE_STA); - vTaskDelay(pdMS_TO_TICKS(500)); - - wifi_config_t wifi_config; - esp_wifi_get_config(WIFI_IF_STA, &wifi_config); - wifi_config.sta.channel = 0; - - esp_wifi_set_config(WIFI_IF_STA, &wifi_config); - esp_wifi_start(); - vTaskDelay(pdMS_TO_TICKS(500)); - esp_wifi_connect(); - - current_wifi_mode = WIFI_MODE_STA_CSI; - status_led_set_state(LED_STATE_WAITING); - wifi_connected = false; - return ESP_OK; -} - // --- Console Commands ---------------------------------------------- static int cmd_mode_monitor(int argc, char **argv) { - int channel = monitor_channel; + int channel = wifi_ctl_get_monitor_channel(); if (argc > 1) channel = atoi(argv[1]); - if (switch_to_monitor_mode(channel, WIFI_BW_HT20) != ESP_OK) { + + if (wifi_ctl_switch_to_monitor(channel, WIFI_BW_HT20) != ESP_OK) { printf("Failed to switch to monitor mode\n"); return 1; } @@ -155,7 +40,7 @@ static int cmd_mode_monitor(int argc, char **argv) { } static int cmd_mode_sta(int argc, char **argv) { - if (switch_to_sta_mode(WIFI_BAND_MODE_AUTO) != ESP_OK) { + if (wifi_ctl_switch_to_sta(WIFI_BAND_MODE_AUTO) != ESP_OK) { printf("Failed to switch to STA mode\n"); return 1; } @@ -165,23 +50,25 @@ static int cmd_mode_sta(int argc, char **argv) { 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" : "MONITOR"); + printf("Current mode: %s\n", wifi_ctl_get_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"); - if (current_wifi_mode == WIFI_MODE_STA_CSI) { + if (wifi_ctl_get_mode() == WIFI_CTL_MODE_STA) { printf("CSI Enabled: %s\n", csi_mgr_is_enabled() ? "Yes" : "No"); printf("CSI Packets: %lu\n", (unsigned long)csi_mgr_get_packet_count()); + } else { + printf("Monitor Channel: %d\n", wifi_ctl_get_monitor_channel()); + printf("Frames Captured: %lu\n", (unsigned long)wifi_ctl_get_monitor_frame_count()); } return 0; } static int cmd_csi_dump(int argc, char **argv) { - if (current_wifi_mode != WIFI_MODE_STA_CSI) { + if (wifi_ctl_get_mode() != WIFI_CTL_MODE_STA) { printf("Error: CSI only available in STA mode\n"); return 1; } - // Uses the new manager to dump - csi_log_dump_over_uart(); + csi_mgr_schedule_dump(); return 0; } @@ -199,31 +86,28 @@ static void register_mode_commands(void) { 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 (has_config && current_wifi_mode == WIFI_MODE_STA_CSI) { + if (wifi_ctl_get_mode() == WIFI_CTL_MODE_STA) { status_led_set_state(LED_STATE_WAITING); } } else if (event_id == WIFI_EVENT_STA_DISCONNECTED) { - wifi_connected = false; - if (has_config && current_wifi_mode == WIFI_MODE_STA_CSI) { + 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)); - wifi_connected = true; status_led_set_state(LED_STATE_CONNECTED); - - // Start CSI Manager (Async) csi_mgr_enable_async(); iperf_cfg_t cfg = { .flag = IPERF_FLAG_SERVER | IPERF_FLAG_TCP, .sport = 5001 }; iperf_start(&cfg); - // Schedule dump if needed (or rely on CLI) csi_mgr_schedule_dump(); } } @@ -237,7 +121,8 @@ void app_main(void) { // Init Subsystems ESP_ERROR_CHECK(csi_log_init()); status_led_init(RGB_LED_GPIO, HAS_RGB_LED); - csi_mgr_init(); // New Init + csi_mgr_init(); + wifi_ctl_init(); // Init GPS const gps_sync_config_t gps_cfg = { @@ -267,27 +152,14 @@ void app_main(void) { // Apply Config if (wifi_cfg_apply_from_nvs()) { - has_config = true; 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) { - uint8_t *ch_param = malloc(sizeof(uint8_t)); - *ch_param = mon_ch; - xTaskCreate(auto_monitor_task, "auto_monitor", 4096, ch_param, 5, NULL); + wifi_ctl_auto_monitor_start(mon_ch); } } else { - has_config = false; status_led_set_state(LED_STATE_NO_CONFIG); } } - -static void auto_monitor_task(void *arg) { - uint8_t channel = *(uint8_t*)arg; - free(arg); - while (status_led_get_state() != LED_STATE_CONNECTED) vTaskDelay(pdMS_TO_TICKS(500)); - vTaskDelay(pdMS_TO_TICKS(2000)); - switch_to_monitor_mode(channel, WIFI_BW_HT20); - vTaskDelete(NULL); -}