diff --git a/components/wifi_cfg/wifi_cfg.c b/components/wifi_cfg/wifi_cfg.c index ea7fed2..f6d3f56 100644 --- a/components/wifi_cfg/wifi_cfg.c +++ b/components/wifi_cfg/wifi_cfg.c @@ -141,6 +141,26 @@ bool wifi_cfg_set_monitor_channel(uint8_t channel) { return (err == ESP_OK); } +bool wifi_cfg_get_monitor_channel(uint8_t *channel_out) { + bool result = false; + + if (channel_out != NULL) { + nvs_handle_t h; + uint8_t saved_val = DEFAULT_MONITOR_CHANNEL; + + if (nvs_open(NVS_NS, NVS_READONLY, &h) == ESP_OK) { + esp_err_t err = nvs_get_u8(h, "mon_chan", &saved_val); + nvs_close(h); + if (err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND) { + *channel_out = saved_val; + result = true; + } + } + } + + return result; +} + void wifi_cfg_clear_monitor_channel(void) { nvs_handle_t h; if (nvs_open(NVS_NS, NVS_READWRITE, &h) == ESP_OK) { diff --git a/components/wifi_cfg/wifi_cfg.h b/components/wifi_cfg/wifi_cfg.h index 5002c15..47f7125 100644 --- a/components/wifi_cfg/wifi_cfg.h +++ b/components/wifi_cfg/wifi_cfg.h @@ -55,6 +55,7 @@ bool wifi_cfg_set_password(const char *password); // Monitor Specific bool wifi_cfg_set_monitor_channel(uint8_t channel); +bool wifi_cfg_get_monitor_channel(uint8_t *channel_out); void wifi_cfg_clear_monitor_channel(void); bool wifi_cfg_monitor_channel_is_unsaved(uint8_t current_val); diff --git a/components/wifi_controller/wifi_controller.c b/components/wifi_controller/wifi_controller.c index e8d2583..0b6e4b4 100644 --- a/components/wifi_controller/wifi_controller.c +++ b/components/wifi_controller/wifi_controller.c @@ -90,6 +90,8 @@ typedef struct { static rate_tracker_t s_telemetry_gen_rate = {0}; static rate_tracker_t s_sd_write_rate = {0}; +static rate_tracker_t s_frame_rate = {0}; +static uint32_t s_last_frame_count_for_rate = 0; /* Batch buffer for telemetry (shared between task and flush function) */ static char s_batch_buf[TELEMETRY_BATCH_SIZE]; @@ -206,6 +208,8 @@ static void monitor_stats_task(void *arg) { uint64_t start_ms = esp_timer_get_time() / 1000; s_telemetry_gen_rate.last_update_ms = start_ms; s_sd_write_rate.last_update_ms = start_ms; + s_frame_rate.last_update_ms = start_ms; + s_last_frame_count_for_rate = s_monitor_frame_count; last_batch_flush_ms = start_ms; last_stats_log_ms = start_ms; @@ -222,6 +226,16 @@ static void monitor_stats_task(void *arg) { if (s_monitor_frame_count == last_frame_count) { status_led_set_capture_active(false); } + + /* Update frame rate tracker */ + uint32_t frames_delta = s_monitor_frame_count - s_last_frame_count_for_rate; + uint32_t frame_interval_ms = (uint32_t)(now_ms - s_frame_rate.last_update_ms); + if (frame_interval_ms > 0) { + update_rate_tracker(&s_frame_rate, frames_delta, frame_interval_ms); + s_frame_rate.last_update_ms = now_ms; + s_last_frame_count_for_rate = s_monitor_frame_count; + } + last_frame_count = s_monitor_frame_count; /* Generate telemetry JSON (regardless of SD card status) */ @@ -422,10 +436,20 @@ void wifi_ctl_init(void) { esp_wifi_connect(); } - // Load Staging Params + // Load Staging and Active Params from NVS 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; + + // Load active channel from NVS (persists across reboots) + uint8_t saved_active_channel = 0; + if (wifi_cfg_get_monitor_channel(&saved_active_channel) && saved_active_channel > 0 && saved_active_channel <= 14) { + s_monitor_channel_active = saved_active_channel; + // Also update staging to match active if staging wasn't set + if (s_monitor_channel_staging == 6) { + s_monitor_channel_staging = saved_active_channel; + } + } } // --- Mode Control (Core) --- @@ -433,7 +457,10 @@ void wifi_ctl_init(void) { esp_err_t wifi_ctl_switch_to_monitor(uint8_t channel, wifi_bandwidth_t bw) { esp_err_t result = ESP_OK; - if (channel == 0) channel = s_monitor_channel_staging; + if (channel == 0) { + // Use active channel if set, otherwise fall back to staging + channel = (s_monitor_channel_active > 0) ? s_monitor_channel_active : s_monitor_channel_staging; + } if (s_current_mode == WIFI_CTL_MODE_MONITOR && s_monitor_channel_active == channel) { ESP_LOGW(TAG, "Already in monitor mode (Ch %d)", channel); @@ -473,14 +500,19 @@ esp_err_t wifi_ctl_switch_to_monitor(uint8_t channel, wifi_bandwidth_t bw) { s_monitor_enabled = true; s_current_mode = WIFI_CTL_MODE_MONITOR; s_monitor_channel_active = channel; + /* Save active channel to NVS so it persists across reboots */ + wifi_cfg_set_monitor_channel(channel); status_led_set_state(LED_STATE_MONITORING); /* Reset rate trackers when starting monitor */ uint64_t start_ms = esp_timer_get_time() / 1000; memset(&s_telemetry_gen_rate, 0, sizeof(rate_tracker_t)); memset(&s_sd_write_rate, 0, sizeof(rate_tracker_t)); + memset(&s_frame_rate, 0, sizeof(rate_tracker_t)); s_telemetry_gen_rate.last_update_ms = start_ms; s_sd_write_rate.last_update_ms = start_ms; + s_frame_rate.last_update_ms = start_ms; + s_last_frame_count_for_rate = s_monitor_frame_count; /* Initialize batch buffer and mutex */ if (s_batch_mutex == NULL) { @@ -583,9 +615,39 @@ void wifi_ctl_set_channel(int channel) { ESP_LOGI(TAG, "Switching live channel to %d", channel); esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); s_monitor_channel_active = (uint8_t)channel; + /* Save active channel to NVS so it persists across reboots */ + wifi_cfg_set_monitor_channel(channel); } } +/** + * @brief Calculate WiFi channel frequency in MHz + * @param channel Channel number (1-14 for 2.4GHz, 36+ for 5GHz) + * @return Frequency in MHz, or 0 if invalid channel + */ +static uint32_t wifi_channel_to_frequency(uint8_t channel) { + uint32_t freq = 0; + + if (channel >= 1 && channel <= 14) { + /* 2.4 GHz band: 2407 + (channel * 5) MHz */ + freq = 2407 + (channel * 5); + } else if (channel >= 36 && channel <= 64) { + /* 5 GHz UNII-1/2A: 5000 + (channel * 5) MHz */ + freq = 5000 + (channel * 5); + } else if (channel >= 100 && channel <= 144) { + /* 5 GHz UNII-2C: 5000 + (channel * 5) MHz */ + freq = 5000 + (channel * 5); + } else if (channel >= 149 && channel <= 165) { + /* 5 GHz UNII-3: 5000 + (channel * 5) MHz */ + freq = 5000 + (channel * 5); + } else if (channel >= 169 && channel <= 177) { + /* 5 GHz UNII-4: 5000 + (channel * 5) MHz */ + freq = 5000 + (channel * 5); + } + + return freq; +} + void wifi_ctl_status(void) { const char *mode_str = (s_current_mode == WIFI_CTL_MODE_MONITOR) ? "MONITOR" : (s_current_mode == WIFI_CTL_MODE_AP) ? "AP" : "STATION"; @@ -593,8 +655,23 @@ void wifi_ctl_status(void) { printf("WiFi Status:\n"); printf(" Mode: %s\n", mode_str); if (s_current_mode == WIFI_CTL_MODE_MONITOR) { - printf(" Channel: %d\n", s_monitor_channel_active); - printf(" Frames: %lu\n", (unsigned long)s_monitor_frame_count); + uint8_t channel = s_monitor_channel_active; + uint32_t freq_mhz = wifi_channel_to_frequency(channel); + + /* Display channel info: channel N (FREQ MHz), width: 20 MHz, center1: FREQ MHz */ + /* Note: Monitor mode currently uses single channel (20 MHz width) */ + if (freq_mhz > 0) { + printf(" Channel: %d (%" PRIu32 " MHz), width: 20 MHz, center1: %" PRIu32 " MHz\n", + channel, freq_mhz, freq_mhz); + } else { + printf(" Channel: %d\n", channel); + } + /* Get frame rate (frames per second) */ + double frame_rate_fps = 0.0; + if (s_frame_rate.sample_count > 0) { + frame_rate_fps = s_frame_rate.mean_rate_bps; /* Already in per-second units for frames */ + } + printf(" Frames: %lu, %.1f fps\n", (unsigned long)s_monitor_frame_count, frame_rate_fps); /* Show telemetry rate statistics */ uint64_t gen_bytes = 0, write_bytes = 0; @@ -625,7 +702,6 @@ void wifi_ctl_status(void) { } } } - printf(" Staging Ch: %d\n", s_monitor_channel_staging); } // --- Params (NVS) --- @@ -636,8 +712,15 @@ bool wifi_ctl_param_is_unsaved(void) { void wifi_ctl_param_save(const char *dummy) { (void)dummy; - if (wifi_cfg_set_monitor_channel(s_monitor_channel_staging)) { - ESP_LOGI(TAG, "Monitor channel (%d) saved to NVS", s_monitor_channel_staging); + /* If monitor mode is running, save the active channel; otherwise save staging */ + uint8_t channel_to_save = (s_current_mode == WIFI_CTL_MODE_MONITOR) ? + s_monitor_channel_active : s_monitor_channel_staging; + if (wifi_cfg_set_monitor_channel(channel_to_save)) { + ESP_LOGI(TAG, "Monitor channel (%d) saved to NVS", channel_to_save); + /* Update staging to match if we saved active */ + if (s_current_mode == WIFI_CTL_MODE_MONITOR) { + s_monitor_channel_staging = channel_to_save; + } } else { ESP_LOGI(TAG, "No changes to save."); } @@ -648,7 +731,17 @@ void wifi_ctl_param_init(void) { 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); + + // Reload active channel from NVS + uint8_t saved_active_channel = 0; + if (wifi_cfg_get_monitor_channel(&saved_active_channel) && saved_active_channel > 0 && saved_active_channel <= 14) { + s_monitor_channel_active = saved_active_channel; + // Update staging to match active if staging wasn't set + if (s_monitor_channel_staging == 6 && ch == 0) { + s_monitor_channel_staging = saved_active_channel; + } + } + ESP_LOGI(TAG, "Reloaded monitor channel: active=%d, staging=%d", s_monitor_channel_active, s_monitor_channel_staging); } void wifi_ctl_param_clear(void) {