ESP32/components/wifi_controller/wifi_controller.c

252 lines
7.2 KiB
C

#include "wifi_controller.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "inttypes.h"
#include "wifi_cfg.h" // Required for apply_from_nvs
// Dependencies
#include "iperf.h"
#include "status_led.h"
#include "wifi_monitor.h"
#include "gps_sync.h"
#ifdef CONFIG_ESP_WIFI_CSI_ENABLED
#include "csi_manager.h"
#endif
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 uint8_t s_monitor_channel_staging = 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();
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++;
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...");
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;
// -------------------------------------------------------------
// CRITICAL FIX: Initialize the WiFi Driver via Config
// This calls esp_wifi_init() and esp_wifi_start()
// -------------------------------------------------------------
if (!wifi_cfg_apply_from_nvs()) {
ESP_LOGW(TAG, "No saved WiFi config found, driver initialized in defaults.");
} else {
ESP_LOGI(TAG, "WiFi driver initialized from NVS.");
}
// Load Staging Params
char mode_ignored[16];
wifi_cfg_get_mode(mode_ignored, &s_monitor_channel_staging);
if (s_monitor_channel_staging == 0) s_monitor_channel_staging = 6;
}
// --- Parameter Management ---
void wifi_ctl_param_set_monitor_channel(uint8_t channel) {
if (channel >= 1 && channel <= 14) {
s_monitor_channel_staging = channel;
}
}
uint8_t wifi_ctl_param_get_monitor_channel(void) {
return s_monitor_channel_staging;
}
bool wifi_ctl_param_save(void) {
bool changed = wifi_cfg_set_monitor_channel(s_monitor_channel_staging);
if (changed) {
ESP_LOGI(TAG, "Monitor channel (%d) saved to NVS", s_monitor_channel_staging);
}
return changed;
}
void wifi_ctl_param_reload(void) {
char mode_ignored[16];
uint8_t ch = 0;
wifi_cfg_get_mode(mode_ignored, &ch);
if (ch > 0) s_monitor_channel_staging = ch;
ESP_LOGI(TAG, "Reloaded monitor channel: %d", s_monitor_channel_staging);
}
bool wifi_ctl_param_is_unsaved(void) {
return wifi_cfg_monitor_channel_is_unsaved(s_monitor_channel_staging);
}
// --- Actions ---
esp_err_t wifi_ctl_switch_to_monitor(uint8_t channel_override, wifi_bandwidth_t bandwidth) {
uint8_t channel = (channel_override > 0) ? channel_override : s_monitor_channel_staging;
if (s_current_mode == WIFI_CTL_MODE_MONITOR && s_monitor_channel == channel) {
ESP_LOGW(TAG, "Already in monitor mode");
return ESP_OK;
}
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);
iperf_stop();
vTaskDelay(pdMS_TO_TICKS(500));
#ifdef CONFIG_ESP_WIFI_CSI_ENABLED
csi_mgr_disable();
#endif
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) {
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;
}
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");
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();
s_current_mode = WIFI_CTL_MODE_STA;
status_led_set_state(LED_STATE_WAITING);
return ESP_OK;
}
void wifi_ctl_param_clear(void) {
// 1. Erase NVS
wifi_cfg_clear_monitor_channel();
// 2. Reset RAM Staging to Default (6)
s_monitor_channel_staging = 6;
ESP_LOGI(TAG, "Monitor configuration cleared (Defaulting to Ch 6).");
}
void wifi_ctl_auto_monitor_start(uint8_t channel) {
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;
}