more on support for esp32, C5 and S3
This commit is contained in:
parent
a84f9a0db6
commit
e350cc2a80
|
|
@ -0,0 +1,3 @@
|
||||||
|
idf_component_register(SRCS "cmd_transport.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
PRIV_REQUIRES console driver soc)
|
||||||
|
|
@ -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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
@ -13,15 +13,11 @@
|
||||||
|
|
||||||
static const char *TAG = "GPS_SYNC";
|
static const char *TAG = "GPS_SYNC";
|
||||||
|
|
||||||
// --- INTERNAL MACROS ---
|
|
||||||
#define GPS_BAUD_RATE 9600
|
#define GPS_BAUD_RATE 9600
|
||||||
#define UART_BUF_SIZE 1024
|
#define UART_BUF_SIZE 1024
|
||||||
|
|
||||||
// --- GLOBAL STATE ---
|
// --- GLOBAL STATE ---
|
||||||
// MUST be defined before gps_task uses it
|
|
||||||
static uart_port_t gps_uart_num = UART_NUM_1;
|
static uart_port_t gps_uart_num = UART_NUM_1;
|
||||||
|
|
||||||
// GPS sync state
|
|
||||||
static int64_t monotonic_offset_us = 0;
|
static int64_t monotonic_offset_us = 0;
|
||||||
static volatile int64_t last_pps_monotonic = 0;
|
static volatile int64_t last_pps_monotonic = 0;
|
||||||
static volatile time_t next_pps_gps_second = 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 SemaphoreHandle_t sync_mutex;
|
||||||
static volatile bool force_sync_update = true;
|
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 void IRAM_ATTR pps_isr_handler(void* arg) {
|
||||||
static bool onetime = true;
|
static bool onetime = true;
|
||||||
last_pps_monotonic = esp_timer_get_time();
|
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) {
|
static bool parse_gprmc(const char* nmea, struct tm* tm_out, bool* valid) {
|
||||||
if (strncmp(nmea, "$GPRMC", 6) != 0 && strncmp(nmea, "$GNRMC", 6) != 0) {
|
if (strncmp(nmea, "$GPRMC", 6) != 0 && strncmp(nmea, "$GNRMC", 6) != 0) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *p = strchr(nmea, ',');
|
char *p = strchr(nmea, ',');
|
||||||
if (!p) return false;
|
if (!p) return false;
|
||||||
|
|
||||||
// Time field
|
|
||||||
p++;
|
p++;
|
||||||
int hour, min, sec;
|
int hour, min, sec;
|
||||||
if (sscanf(p, "%2d%2d%2d", &hour, &min, &sec) != 3) {
|
if (sscanf(p, "%2d%2d%2d", &hour, &min, &sec) != 3) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status field (A=valid, V=invalid)
|
|
||||||
p = strchr(p, ',');
|
p = strchr(p, ',');
|
||||||
if (!p) return false;
|
if (!p) return false;
|
||||||
p++;
|
p++;
|
||||||
*valid = (*p == 'A');
|
*valid = (*p == 'A');
|
||||||
|
|
||||||
// Skip to date field (8 commas ahead from time)
|
|
||||||
for (int i = 0; i < 7; i++) {
|
for (int i = 0; i < 7; i++) {
|
||||||
p = strchr(p, ',');
|
p = strchr(p, ',');
|
||||||
if (!p) return false;
|
if (!p) return false;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Date field: ddmmyy
|
|
||||||
int day, month, year;
|
int day, month, year;
|
||||||
if (sscanf(p, "%2d%2d%2d", &day, &month, &year) != 3) {
|
if (sscanf(p, "%2d%2d%2d", &day, &month, &year) != 3) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
year += (year < 80) ? 2000 : 1900;
|
year += (year < 80) ? 2000 : 1900;
|
||||||
|
|
||||||
tm_out->tm_sec = sec;
|
tm_out->tm_sec = sec;
|
||||||
tm_out->tm_min = min;
|
tm_out->tm_min = min;
|
||||||
tm_out->tm_hour = hour;
|
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_mon = month - 1;
|
||||||
tm_out->tm_year = year - 1900;
|
tm_out->tm_year = year - 1900;
|
||||||
tm_out->tm_isdst = 0;
|
tm_out->tm_isdst = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force the next GPS update to snap immediately (bypass filter)
|
|
||||||
void gps_force_next_update(void) {
|
void gps_force_next_update(void) {
|
||||||
force_sync_update = true;
|
force_sync_update = true;
|
||||||
ESP_LOGW(TAG, "Requesting forced GPS sync update");
|
ESP_LOGW(TAG, "Requesting forced GPS sync update");
|
||||||
}
|
}
|
||||||
|
|
||||||
// GPS processing task
|
|
||||||
static void gps_task(void* arg) {
|
static void gps_task(void* arg) {
|
||||||
// Buffer for UART reads (more efficient than reading 1 byte at a time)
|
|
||||||
uint8_t d_buf[64];
|
uint8_t d_buf[64];
|
||||||
char line[128];
|
char line[128];
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
static int log_counter = 0; // Counter to throttle logs
|
static int log_counter = 0;
|
||||||
|
|
||||||
while (1) {
|
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));
|
int len = uart_read_bytes(gps_uart_num, d_buf, sizeof(d_buf), pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
// Process all bytes received in this batch
|
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
uint8_t data = d_buf[i];
|
uint8_t data = d_buf[i];
|
||||||
|
|
||||||
if (data == '\n') {
|
if (data == '\n') {
|
||||||
line[pos] = '\0';
|
line[pos] = '\0';
|
||||||
|
|
||||||
struct tm gps_tm;
|
struct tm gps_tm;
|
||||||
bool valid;
|
bool valid;
|
||||||
if (parse_gprmc(line, &gps_tm, &valid)) {
|
if (parse_gprmc(line, &gps_tm, &valid)) {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
time_t gps_time = mktime(&gps_tm);
|
time_t gps_time = mktime(&gps_tm);
|
||||||
|
|
||||||
xSemaphoreTake(sync_mutex, portMAX_DELAY);
|
xSemaphoreTake(sync_mutex, portMAX_DELAY);
|
||||||
next_pps_gps_second = gps_time + 1;
|
next_pps_gps_second = gps_time + 1;
|
||||||
xSemaphoreGive(sync_mutex);
|
xSemaphoreGive(sync_mutex);
|
||||||
|
|
||||||
// Wait a bit to ensure PPS has likely fired if it was going to
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(300));
|
vTaskDelay(pdMS_TO_TICKS(300));
|
||||||
|
|
||||||
xSemaphoreTake(sync_mutex, portMAX_DELAY);
|
xSemaphoreTake(sync_mutex, portMAX_DELAY);
|
||||||
if (last_pps_monotonic > 0) {
|
if (last_pps_monotonic > 0) {
|
||||||
int64_t gps_us = (int64_t)next_pps_gps_second * 1000000LL;
|
int64_t gps_us = (int64_t)next_pps_gps_second * 1000000LL;
|
||||||
int64_t new_offset = gps_us - last_pps_monotonic;
|
int64_t new_offset = gps_us - last_pps_monotonic;
|
||||||
|
|
||||||
if (monotonic_offset_us == 0 || force_sync_update) {
|
if (monotonic_offset_us == 0 || force_sync_update) {
|
||||||
monotonic_offset_us = new_offset;
|
monotonic_offset_us = new_offset;
|
||||||
|
|
||||||
if (force_sync_update) {
|
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;
|
force_sync_update = false;
|
||||||
log_counter = 0; // Ensure we see the log immediately after a snap
|
log_counter = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Low-pass filter: 90% old + 10% new
|
|
||||||
monotonic_offset_us = (monotonic_offset_us * 9 + new_offset) / 10;
|
monotonic_offset_us = (monotonic_offset_us * 9 + new_offset) / 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
gps_has_fix = true;
|
gps_has_fix = true;
|
||||||
|
|
||||||
// LOGGING THROTTLE: Only print every 60th update (approx 60 seconds)
|
|
||||||
if (log_counter == 0) {
|
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_year + 1900, gps_tm.tm_mon + 1, gps_tm.tm_mday,
|
||||||
gps_tm.tm_hour, gps_tm.tm_min, gps_tm.tm_sec,
|
gps_tm.tm_hour, gps_tm.tm_min, gps_tm.tm_sec,
|
||||||
monotonic_offset_us);
|
monotonic_offset_us);
|
||||||
|
|
@ -162,7 +124,6 @@ static void gps_task(void* arg) {
|
||||||
gps_has_fix = false;
|
gps_has_fix = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
} else if (pos < sizeof(line) - 1) {
|
} else if (pos < sizeof(line) - 1) {
|
||||||
line[pos++] = data;
|
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) {
|
void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps) {
|
||||||
ESP_LOGI(TAG, "Initializing GPS sync");
|
ESP_LOGI(TAG, "Initializing GPS sync");
|
||||||
|
|
||||||
// 1. Store the UART port for the task to use
|
|
||||||
gps_uart_num = config->uart_port;
|
gps_uart_num = config->uart_port;
|
||||||
use_gps_for_logs = use_gps_log_timestamps;
|
use_gps_for_logs = use_gps_log_timestamps;
|
||||||
|
|
||||||
// Ensure we start with a forced update
|
|
||||||
gps_force_next_update();
|
gps_force_next_update();
|
||||||
|
|
||||||
if (use_gps_log_timestamps) {
|
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();
|
sync_mutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
// 2. Configure UART
|
|
||||||
uart_config_t uart_config = {
|
uart_config_t uart_config = {
|
||||||
.baud_rate = GPS_BAUD_RATE,
|
.baud_rate = GPS_BAUD_RATE,
|
||||||
.data_bits = UART_DATA_8_BITS,
|
.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_driver_install(config->uart_port, UART_BUF_SIZE, 0, 0, NULL, 0));
|
||||||
ESP_ERROR_CHECK(uart_param_config(config->uart_port, &uart_config));
|
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,
|
ESP_ERROR_CHECK(uart_set_pin(config->uart_port,
|
||||||
config->tx_pin,
|
config->tx_pin,
|
||||||
config->rx_pin,
|
config->rx_pin,
|
||||||
UART_PIN_NO_CHANGE,
|
UART_PIN_NO_CHANGE,
|
||||||
UART_PIN_NO_CHANGE));
|
UART_PIN_NO_CHANGE));
|
||||||
|
|
||||||
// 4. Configure PPS GPIO
|
|
||||||
gpio_config_t io_conf = {
|
gpio_config_t io_conf = {
|
||||||
.intr_type = GPIO_INTR_POSEDGE,
|
.intr_type = GPIO_INTR_POSEDGE,
|
||||||
.mode = GPIO_MODE_INPUT,
|
.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));
|
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||||
|
|
||||||
// 5. Install ISR
|
|
||||||
gpio_install_isr_service(0);
|
gpio_install_isr_service(0);
|
||||||
ESP_ERROR_CHECK(gpio_isr_handler_add(config->pps_pin, pps_isr_handler, NULL));
|
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);
|
config->uart_port, config->rx_pin, config->tx_pin, config->pps_pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gps_timestamp_t gps_get_timestamp(void) {
|
gps_timestamp_t gps_get_timestamp(void) {
|
||||||
gps_timestamp_t ts;
|
gps_timestamp_t ts;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/uart.h"
|
#include "driver/uart.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include <stdbool.h>
|
||||||
#include "freertos/semphr.h"
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uart_port_t uart_port;
|
uart_port_t uart_port;
|
||||||
|
|
@ -16,21 +13,18 @@ typedef struct {
|
||||||
} gps_sync_config_t;
|
} gps_sync_config_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int64_t monotonic_us; // Microseconds - never jumps backward
|
int64_t monotonic_us;
|
||||||
int64_t monotonic_ms; // Milliseconds - for easier logging
|
int64_t monotonic_ms;
|
||||||
int64_t gps_us; // GPS UTC time in microseconds
|
int64_t gps_us;
|
||||||
int64_t gps_ms; // GPS UTC time in milliseconds
|
int64_t gps_ms;
|
||||||
struct timespec mono_ts; // POSIX timespec
|
struct timespec mono_ts;
|
||||||
bool synced; // true if GPS has valid fix
|
bool synced;
|
||||||
} gps_timestamp_t;
|
} gps_timestamp_t;
|
||||||
|
|
||||||
void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps);
|
void gps_sync_init(const gps_sync_config_t *config, bool use_gps_log_timestamps);
|
||||||
|
|
||||||
void gps_force_next_update(void);
|
void gps_force_next_update(void);
|
||||||
gps_timestamp_t gps_get_timestamp(void);
|
gps_timestamp_t gps_get_timestamp(void);
|
||||||
int64_t gps_get_monotonic_ms(void);
|
int64_t gps_get_monotonic_ms(void);
|
||||||
bool gps_is_synced(void);
|
bool gps_is_synced(void);
|
||||||
|
|
||||||
// Internal logging hooks
|
|
||||||
uint32_t gps_log_timestamp(void);
|
uint32_t gps_log_timestamp(void);
|
||||||
int gps_log_vprintf(const char *fmt, va_list args);
|
int gps_log_vprintf(const char *fmt, va_list args);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,3 @@
|
||||||
idf_component_register(
|
idf_component_register(SRCS "wifi_cfg.c"
|
||||||
SRCS "wifi_cfg.c"
|
INCLUDE_DIRS "."
|
||||||
INCLUDE_DIRS "."
|
PRIV_REQUIRES nvs_flash esp_wifi esp_netif driver cmd_transport)
|
||||||
REQUIRES
|
|
||||||
esp_wifi
|
|
||||||
esp_netif
|
|
||||||
nvs_flash
|
|
||||||
esp_event
|
|
||||||
driver
|
|
||||||
esp_driver_usb_serial_jtag
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -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 <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "nvs.h"
|
#include "nvs.h"
|
||||||
|
|
@ -23,25 +12,15 @@
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_check.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"
|
#include "wifi_cfg.h"
|
||||||
|
#include "cmd_transport.h" // Now uses the transport component
|
||||||
|
|
||||||
// wifi_cfg.c
|
|
||||||
|
|
||||||
static const char *TAG = "wifi_cfg";
|
static const char *TAG = "wifi_cfg";
|
||||||
|
|
||||||
static esp_netif_t *sta_netif = NULL;
|
static esp_netif_t *sta_netif = NULL;
|
||||||
static bool cfg_dhcp = true;
|
static bool cfg_dhcp = true;
|
||||||
|
|
||||||
static void trim(char *s){
|
// --- Helper Functions (Preserved) ---
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t nvs_set_str2(nvs_handle_t h, const char *key, const char *val){
|
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);
|
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_commit(h);
|
||||||
nvs_close(h);
|
nvs_close(h);
|
||||||
cfg_dhcp = dhcp;
|
cfg_dhcp = dhcp;
|
||||||
ESP_LOGI(TAG, "Config saved to NVS: SSID=%s Mode=%s MonCh=%d Band=%s BW=%s PowerSave=%s",
|
ESP_LOGI(TAG, "Config saved to NVS: SSID=%s Mode=%s MonCh=%d", ssid?ssid:"", mode?mode:"STA", mon_ch);
|
||||||
ssid?ssid:"", mode?mode:"STA", mon_ch, band?band:"", bw?bw:"", powersave?powersave:"NONE");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool load_cfg(char* ssid, size_t ssz, char* pass, size_t psz,
|
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) {
|
bool wifi_cfg_get_mode(char *mode, uint8_t *mon_ch) {
|
||||||
if (!mode || !mon_ch) return false;
|
if (!mode || !mon_ch) return false;
|
||||||
|
|
||||||
nvs_handle_t h;
|
nvs_handle_t h;
|
||||||
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) {
|
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;
|
size_t len = 16;
|
||||||
esp_err_t e = nvs_get_str(h, "mode", mode, &len);
|
if (nvs_get_str(h, "mode", mode, &len) != ESP_OK) strcpy(mode, "STA");
|
||||||
if (e != ESP_OK) {
|
|
||||||
strcpy(mode, "STA"); // Default to STA mode
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ch = 36;
|
uint8_t ch = 36;
|
||||||
nvs_get_u8(h, "mon_ch", &ch);
|
nvs_get_u8(h, "mon_ch", &ch);
|
||||||
*mon_ch = ch;
|
*mon_ch = ch;
|
||||||
|
|
||||||
nvs_close(h);
|
nvs_close(h);
|
||||||
ESP_LOGI(TAG, "Retrieved mode from NVS: %s (MonCh=%d)", mode, ch);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* --- One-time net stack bring-up (thread-safe) --- */
|
|
||||||
static atomic_bool s_net_stack_ready = false;
|
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;
|
bool expected = false;
|
||||||
if (atomic_compare_exchange_strong(&s_net_stack_ready, &expected, true)) {
|
if (atomic_compare_exchange_strong(&s_net_stack_ready, &expected, true)) {
|
||||||
ESP_RETURN_ON_ERROR(esp_netif_init(), TAG, "esp_netif_init");
|
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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- One-time Wi-Fi driver init (thread-safe, idempotent) --- */
|
|
||||||
static atomic_bool s_wifi_inited = false;
|
static atomic_bool s_wifi_inited = false;
|
||||||
|
esp_err_t wifi_ensure_inited(void) {
|
||||||
esp_err_t wifi_ensure_inited(void)
|
|
||||||
{
|
|
||||||
bool expected = false;
|
bool expected = false;
|
||||||
if (!atomic_compare_exchange_strong(&s_wifi_inited, &expected, true)) {
|
if (!atomic_compare_exchange_strong(&s_wifi_inited, &expected, true)) return ESP_OK;
|
||||||
// someone else already initialized (or is initializing and finished)
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(ensure_net_stack_once(), TAG, "net stack");
|
ESP_RETURN_ON_ERROR(ensure_net_stack_once(), TAG, "net stack");
|
||||||
|
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
esp_err_t err = esp_wifi_init(&cfg);
|
esp_err_t err = esp_wifi_init(&cfg);
|
||||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
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);
|
atomic_store(&s_wifi_inited, false);
|
||||||
ESP_RETURN_ON_ERROR(err, TAG, "esp_wifi_init");
|
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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void apply_ip_static(const char* ip, const char* mask, const char* gw){
|
static void apply_ip_static(const char* ip, const char* mask, const char* gw){
|
||||||
if (!sta_netif) return;
|
if (!sta_netif) return;
|
||||||
|
if (!ip || !ip[0] || !mask || !mask[0] || !gw || !gw[0]) 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_netif_ip_info_t info = {0};
|
esp_netif_ip_info_t info = {0};
|
||||||
esp_netif_dhcpc_stop(sta_netif);
|
esp_netif_dhcpc_stop(sta_netif);
|
||||||
info.ip.addr = esp_ip4addr_aton(ip);
|
info.ip.addr = esp_ip4addr_aton(ip);
|
||||||
info.netmask.addr = esp_ip4addr_aton(mask);
|
info.netmask.addr = esp_ip4addr_aton(mask);
|
||||||
info.gw.addr = esp_ip4addr_aton(gw);
|
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) );
|
ESP_ERROR_CHECK( esp_netif_set_ip_info(sta_netif, &info) );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wifi_cfg_apply_from_nvs(void) {
|
bool wifi_cfg_apply_from_nvs(void) {
|
||||||
char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0};
|
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};
|
char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0};
|
||||||
uint8_t mon_ch = 36;
|
uint8_t mon_ch = 36; bool dhcp = true;
|
||||||
bool dhcp = true;
|
|
||||||
if (!load_cfg(ssid,sizeof(ssid), pass,sizeof(pass), ip,sizeof(ip), mask,sizeof(mask), gw,sizeof(gw),
|
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)){
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
// Treat empty SSID as "no config" to avoid ESP_ERR_WIFI_SSID panics
|
if (ssid[0] == '\0') return false;
|
||||||
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);
|
|
||||||
|
|
||||||
static bool inited = false;
|
static bool inited = false;
|
||||||
if (!inited){
|
if (!inited){
|
||||||
// NVS (with recovery)
|
nvs_flash_init();
|
||||||
esp_err_t err = nvs_flash_init();
|
ensure_net_stack_once();
|
||||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
if (sta_netif == NULL) sta_netif = esp_netif_create_default_wifi_sta();
|
||||||
nvs_flash_erase();
|
wifi_ensure_inited();
|
||||||
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); }
|
|
||||||
|
|
||||||
inited = true;
|
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.ssid, ssid, sizeof(wcfg.sta.ssid)-1);
|
||||||
strncpy((char*)wcfg.sta.password, pass, sizeof(wcfg.sta.password)-1);
|
strncpy((char*)wcfg.sta.password, pass, sizeof(wcfg.sta.password)-1);
|
||||||
wcfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
wcfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
||||||
wcfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH;
|
wcfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH;
|
||||||
|
|
||||||
// Set scan method to search all channels
|
|
||||||
wcfg.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
|
wcfg.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
|
||||||
|
|
||||||
// Log and configure band preference
|
if (strcmp(band, "5G") == 0) wcfg.sta.channel = 0;
|
||||||
if (strcmp(band, "5G") == 0) {
|
else wcfg.sta.channel = 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
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
esp_wifi_set_mode(WIFI_MODE_STA);
|
||||||
|
|
||||||
// Configure WiFi protocols based on chip capabilities
|
// Protocol selection based on target
|
||||||
#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6
|
#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6
|
||||||
// Dual-band chips (2.4GHz + 5GHz support)
|
|
||||||
wifi_protocols_t protocols = {
|
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,
|
||||||
.ghz_2g = WIFI_PROTOCOL_11B |
|
.ghz_5g = WIFI_PROTOCOL_11A | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11AC | WIFI_PROTOCOL_11AX,
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK( esp_wifi_set_protocols(WIFI_IF_STA, &protocols) );
|
esp_wifi_set_protocols(WIFI_IF_STA, &protocols);
|
||||||
#else
|
#else
|
||||||
// Single-band chips (2.4GHz only) - ESP32, ESP32-S2, ESP32-S3, ESP32-C3, etc.
|
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
|
||||||
// Use legacy API for 2.4GHz-only chips
|
#endif
|
||||||
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) );
|
|
||||||
|
|
||||||
// Warn if user requested 5GHz on a 2.4GHz-only chip
|
esp_wifi_set_config(WIFI_IF_STA, &wcfg);
|
||||||
if (strcmp(band, "5G") == 0) {
|
|
||||||
ESP_LOGW(TAG, "5GHz requested but this chip only supports 2.4GHz - using 2.4GHz");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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]){
|
// Bandwidth selection
|
||||||
apply_ip_static(ip, mask, gw);
|
#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6
|
||||||
} else {
|
wifi_bandwidths_t bandwidths = {.ghz_2g = WIFI_BW_HT20, .ghz_5g = WIFI_BW_HT20};
|
||||||
if (sta_netif) esp_netif_dhcpc_start(sta_netif);
|
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);
|
||||||
// Set bandwidth BEFORE WiFi is started
|
#else
|
||||||
#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
|
|
||||||
wifi_bandwidth_t bandwidth = WIFI_BW_HT20;
|
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_wifi_start();
|
||||||
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_err_t bw_err = esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth);
|
// Power Save
|
||||||
if (bw_err != ESP_OK) {
|
wifi_ps_type_t ps_mode = WIFI_PS_NONE;
|
||||||
ESP_LOGW(TAG, "Failed to set bandwidth: %s", esp_err_to_name(bw_err));
|
if (strcmp(powersave, "MIN") == 0) ps_mode = WIFI_PS_MIN_MODEM;
|
||||||
}
|
else if (strcmp(powersave, "MAX") == 0) ps_mode = WIFI_PS_MAX_MODEM;
|
||||||
#endif
|
esp_wifi_set_ps(ps_mode);
|
||||||
|
|
||||||
esp_err_t err2 = esp_wifi_start();
|
esp_wifi_connect();
|
||||||
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); }
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------- Dual input paths --------------------
|
// --- Command Listener Logic ---
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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){
|
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; }
|
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; }
|
if (strncmp(line, "DHCP:",5)==0){ *dhcp = atoi(line+5) ? true:false; return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cfg_worker(const cfg_io_t *io){
|
static bool wifi_cfg_cmd_handler(const char *line, cmd_reply_func_t reply_func, void *reply_ctx) {
|
||||||
char line[160];
|
static bool in_cfg = false;
|
||||||
char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0};
|
static 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};
|
static char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0};
|
||||||
uint8_t mon_ch = 36;
|
static uint8_t mon_ch = 36;
|
||||||
bool dhcp = true;
|
static bool dhcp = true;
|
||||||
bool in_cfg = false;
|
|
||||||
|
|
||||||
for(;;){
|
if (!in_cfg) {
|
||||||
if (!io->fetch_line(line, sizeof(line), io->ctx)){
|
if (strcmp(line, "CFG") == 0) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(20));
|
in_cfg = true;
|
||||||
continue;
|
// 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);
|
return false; // Not handled
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ---- UART(stdin) path ----
|
// Inside CFG block
|
||||||
static bool uart_fetch_line(char *buf, size_t sz, void *ctx){
|
if (strcmp(line, "END") == 0) {
|
||||||
(void)ctx;
|
// Apply Defaults
|
||||||
if (!fgets(buf, sz, stdin)) return false;
|
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;
|
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<n; ++i){
|
|
||||||
char c = (char)tmp[i];
|
|
||||||
if (c == '\n' || c == '\r'){
|
|
||||||
acc[acc_len] = 0;
|
|
||||||
strncpy(buf, acc, sz-1);
|
|
||||||
buf[sz-1]=0;
|
|
||||||
acc_len = 0;
|
|
||||||
return true;
|
|
||||||
}else if (acc_len < sizeof(acc)-1){
|
|
||||||
acc[acc_len++] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
static void usb_emit(const char *s, void *ctx){
|
|
||||||
(void)ctx;
|
|
||||||
usb_serial_jtag_write_bytes((const uint8_t*)s, strlen(s), pdMS_TO_TICKS(50));
|
|
||||||
}
|
|
||||||
static void cfg_listener_usb_task(void *arg){
|
|
||||||
// Install USB-Serial/JTAG driver (no VFS remap: stdio stays on UART)
|
|
||||||
usb_serial_jtag_driver_config_t d = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
|
|
||||||
ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&d));
|
|
||||||
|
|
||||||
usb_ctx_t uctx = {0};
|
|
||||||
cfg_io_t io = {.emit = usb_emit, .ctx = &uctx, .fetch_line = usb_fetch_line};
|
|
||||||
cfg_worker(&io);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wifi_cfg_init(void){
|
void wifi_cfg_init(void){
|
||||||
// Make sure NVS exists
|
|
||||||
nvs_flash_init();
|
nvs_flash_init();
|
||||||
|
|
||||||
// Spawn both listeners
|
// Init the shared transport (starts UART/USB tasks)
|
||||||
xTaskCreatePinnedToCore(cfg_listener_uart_task, "cfg_uart",
|
cmd_transport_init();
|
||||||
6144, NULL, 5, NULL, tskNO_AFFINITY);
|
|
||||||
xTaskCreatePinnedToCore(cfg_listener_usb_task, "cfg_usb",
|
// Register our callback to catch "CFG" blocks
|
||||||
6144, NULL, 5, NULL, tskNO_AFFINITY);
|
cmd_transport_register_listener(wifi_cfg_cmd_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi_ps_type_t wifi_cfg_get_power_save_mode(void) {
|
wifi_ps_type_t wifi_cfg_get_power_save_mode(void) {
|
||||||
char powersave[16] = {0};
|
char powersave[16] = {0};
|
||||||
nvs_handle_t h;
|
nvs_handle_t h;
|
||||||
|
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) return WIFI_PS_NONE;
|
||||||
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) {
|
|
||||||
ESP_LOGW(TAG, "Failed to open NVS for power save - defaulting to NONE");
|
|
||||||
return WIFI_PS_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = sizeof(powersave);
|
size_t len = sizeof(powersave);
|
||||||
esp_err_t err = nvs_get_str(h, "powersave", powersave, &len);
|
nvs_get_str(h, "powersave", powersave, &len);
|
||||||
nvs_close(h);
|
nvs_close(h);
|
||||||
|
|
||||||
if (err != ESP_OK) {
|
if (strcmp(powersave, "MIN") == 0) return WIFI_PS_MIN_MODEM;
|
||||||
ESP_LOGI(TAG, "No power save setting in NVS - defaulting to NONE");
|
if (strcmp(powersave, "MAX") == 0) return WIFI_PS_MAX_MODEM;
|
||||||
return WIFI_PS_NONE;
|
return WIFI_PS_NONE;
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the power save string
|
|
||||||
if (strcmp(powersave, "MIN") == 0 || strcmp(powersave, "MIN_MODEM") == 0) {
|
|
||||||
ESP_LOGI(TAG, "Power save mode: MIN_MODEM");
|
|
||||||
return WIFI_PS_MIN_MODEM;
|
|
||||||
} else if (strcmp(powersave, "MAX") == 0 || strcmp(powersave, "MAX_MODEM") == 0) {
|
|
||||||
ESP_LOGI(TAG, "Power save mode: MAX_MODEM");
|
|
||||||
return WIFI_PS_MAX_MODEM;
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(TAG, "Power save mode: NONE (no power saving)");
|
|
||||||
return WIFI_PS_NONE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wifi_cfg_get_bandwidth(char *buf, size_t buf_size) {
|
bool wifi_cfg_get_bandwidth(char *buf, size_t buf_size) {
|
||||||
if (!buf || buf_size < 1) {
|
if (!buf || buf_size < 1) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvs_handle_t h;
|
nvs_handle_t h;
|
||||||
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) {
|
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) {
|
||||||
strncpy(buf, "Unknown", buf_size - 1);
|
strncpy(buf, "Unknown", buf_size); return false;
|
||||||
buf[buf_size - 1] = '\0';
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = buf_size;
|
size_t len = buf_size;
|
||||||
esp_err_t err = nvs_get_str(h, "bw", buf, &len);
|
esp_err_t err = nvs_get_str(h, "bw", buf, &len);
|
||||||
nvs_close(h);
|
nvs_close(h);
|
||||||
|
return (err == ESP_OK);
|
||||||
if (err != ESP_OK) {
|
|
||||||
strncpy(buf, "HT20", buf_size - 1); // Default
|
|
||||||
buf[buf_size - 1] = '\0';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
365
main/main.c
365
main/main.c
|
|
@ -1,5 +1,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
|
|
@ -25,12 +26,14 @@
|
||||||
#include "csi_log.h"
|
#include "csi_log.h"
|
||||||
#include "wifi_monitor.h"
|
#include "wifi_monitor.h"
|
||||||
#include "gps_sync.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 ---
|
// --- Hardware Configuration ---
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
// ESP32-S3 Specific Wiring
|
// 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_TX_PIN GPIO_NUM_5
|
||||||
#define GPS_RX_PIN GPIO_NUM_4
|
#define GPS_RX_PIN GPIO_NUM_4
|
||||||
#define GPS_PPS_PIN GPIO_NUM_6
|
#define GPS_PPS_PIN GPIO_NUM_6
|
||||||
|
|
@ -53,23 +56,17 @@
|
||||||
#else
|
#else
|
||||||
// Fallback / Other Chips (C6, etc.)
|
// Fallback / Other Chips (C6, etc.)
|
||||||
#define RGB_LED_GPIO 8
|
#define RGB_LED_GPIO 8
|
||||||
#define GPS_TX_PIN GPIO_NUM_24
|
#define GPS_TX_PIN GPIO_NUM_1
|
||||||
#define GPS_RX_PIN GPIO_NUM_23
|
#define GPS_RX_PIN GPIO_NUM_3
|
||||||
#define GPS_PPS_PIN GPIO_NUM_25
|
#define GPS_PPS_PIN GPIO_NUM_5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char *TAG = "MAIN";
|
|
||||||
|
|
||||||
|
|
||||||
// --- WiFi Operation Mode ---
|
// --- WiFi Operation Mode ---
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WIFI_MODE_STA_CSI, // STA mode: Connected to AP, CSI + iperf (DEFAULT)
|
WIFI_MODE_STA_CSI, // STA mode: Connected to AP, CSI + iperf (DEFAULT)
|
||||||
WIFI_MODE_MONITOR // Monitor mode: Promiscuous, collapse detection
|
WIFI_MODE_MONITOR // Monitor mode: Promiscuous, collapse detection
|
||||||
} wifi_operation_mode_t;
|
} 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_operation_mode_t current_wifi_mode = WIFI_MODE_STA_CSI;
|
||||||
static wifi_band_mode_t preferred_band = WIFI_BAND_MODE_AUTO;
|
static wifi_band_mode_t preferred_band = WIFI_BAND_MODE_AUTO;
|
||||||
static uint8_t monitor_channel = 6; // Default monitor channel
|
static uint8_t monitor_channel = 6; // Default monitor channel
|
||||||
|
|
@ -150,9 +147,8 @@ static void led_task(void *arg) {
|
||||||
// --- GPS Logging Helper ---
|
// --- GPS Logging Helper ---
|
||||||
void log_collapse_event(float nav_duration_us, int rssi, int retry) {
|
void log_collapse_event(float nav_duration_us, int rssi, int retry) {
|
||||||
gps_timestamp_t ts = gps_get_timestamp();
|
gps_timestamp_t ts = gps_get_timestamp();
|
||||||
|
|
||||||
// Format: COLLAPSE,MonoMS,GpsMS,Synced,Duration,RSSI,Retry
|
// 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.monotonic_ms,
|
||||||
ts.gps_ms,
|
ts.gps_ms,
|
||||||
ts.synced ? 1 : 0,
|
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);
|
ESP_LOGI("CSI", "Captured %lu CSI packets", (unsigned long)s_csi_packet_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wifi_enable_csi_once(void) {
|
static void wifi_enable_csi_once(void) {
|
||||||
if (s_csi_enabled) return;
|
if (s_csi_enabled) return;
|
||||||
|
|
||||||
|
|
@ -257,7 +254,7 @@ static void monitor_stats_task(void *arg) {
|
||||||
wifi_collapse_stats_t stats;
|
wifi_collapse_stats_t stats;
|
||||||
if (wifi_monitor_get_stats(&stats) == ESP_OK) {
|
if (wifi_monitor_get_stats(&stats) == ESP_OK) {
|
||||||
ESP_LOGI("MONITOR", "--- Stats: %lu frames, Retry Rate: %.2f%%, Avg NAV: %u us ---",
|
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()) {
|
if (wifi_monitor_is_collapsed()) {
|
||||||
ESP_LOGW("MONITOR", "⚠️ ⚠️ ⚠️ WiFi COLLAPSE DETECTED! ⚠️ ⚠️ ⚠️ ");
|
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;
|
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) {
|
if (bandwidth != WIFI_BW_HT20) {
|
||||||
ESP_LOGW(TAG, "Monitor mode typically restricted to 20MHz capture width");
|
ESP_LOGW(TAG, "Monitor mode typically restricted to 20MHz capture width");
|
||||||
ESP_LOGW(TAG, "Forcing bandwidth to 20MHz (driver limitation)");
|
ESP_LOGW(TAG, "Forcing bandwidth to 20MHz (driver limitation)");
|
||||||
bandwidth = WIFI_BW_HT20;
|
bandwidth = WIFI_BW_HT20;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect band for informational logging
|
|
||||||
const char* band_str = "2.4GHz";
|
const char* band_str = "2.4GHz";
|
||||||
if (channel >= 36 && channel <= 165) {
|
if (channel >= 36 && channel <= 165) {
|
||||||
band_str = "5GHz";
|
band_str = "5GHz";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* bw_str = "20MHz";
|
const char* bw_str = "20MHz";
|
||||||
// Note: Monitor mode typically limited to 20MHz by ESP-IDF drivers
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "========================================");
|
ESP_LOGI(TAG, "========================================");
|
||||||
ESP_LOGI(TAG, "Switching to MONITOR MODE");
|
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, " Bandwidth: %s (monitor mode limitation)", bw_str);
|
||||||
ESP_LOGI(TAG, "========================================");
|
ESP_LOGI(TAG, "========================================");
|
||||||
|
|
||||||
// 1. Stop iperf if running
|
|
||||||
ESP_LOGI(TAG, "Stopping iperf...");
|
ESP_LOGI(TAG, "Stopping iperf...");
|
||||||
iperf_stop();
|
iperf_stop();
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
// 2. Disable CSI
|
|
||||||
wifi_disable_csi();
|
wifi_disable_csi();
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
// 3. Disconnect from AP
|
|
||||||
ESP_LOGI(TAG, "Disconnecting from AP...");
|
ESP_LOGI(TAG, "Disconnecting from AP...");
|
||||||
esp_wifi_disconnect();
|
esp_wifi_disconnect();
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
|
||||||
// 4. Stop WiFi
|
|
||||||
ESP_LOGI(TAG, "Stopping WiFi...");
|
ESP_LOGI(TAG, "Stopping WiFi...");
|
||||||
esp_wifi_stop();
|
esp_wifi_stop();
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
// 5. Set to NULL mode
|
|
||||||
ESP_LOGI(TAG, "Setting WiFi mode to NULL...");
|
ESP_LOGI(TAG, "Setting WiFi mode to NULL...");
|
||||||
esp_wifi_set_mode(WIFI_MODE_NULL);
|
esp_wifi_set_mode(WIFI_MODE_NULL);
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
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...");
|
ESP_LOGI(TAG, "Starting monitor mode...");
|
||||||
if (wifi_monitor_init(channel, monitor_frame_callback) != ESP_OK) {
|
if (wifi_monitor_init(channel, monitor_frame_callback) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to init monitor mode");
|
ESP_LOGE(TAG, "Failed to init monitor mode");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set bandwidth after init
|
|
||||||
esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth);
|
esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth);
|
||||||
|
|
||||||
if (wifi_monitor_start() != ESP_OK) {
|
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;
|
current_led_state = LED_STATE_MONITORING;
|
||||||
monitor_channel = channel;
|
monitor_channel = channel;
|
||||||
|
|
||||||
// 8. Start stats task
|
|
||||||
if (s_monitor_stats_task_handle == NULL) {
|
if (s_monitor_stats_task_handle == NULL) {
|
||||||
xTaskCreate(monitor_stats_task, "monitor_stats", 4096, NULL, 5, &s_monitor_stats_task_handle);
|
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;
|
preferred_band = band_mode;
|
||||||
|
|
||||||
// 1. Stop monitor stats task
|
|
||||||
if (s_monitor_stats_task_handle != NULL) {
|
if (s_monitor_stats_task_handle != NULL) {
|
||||||
vTaskDelete(s_monitor_stats_task_handle);
|
vTaskDelete(s_monitor_stats_task_handle);
|
||||||
s_monitor_stats_task_handle = NULL;
|
s_monitor_stats_task_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Stop monitor mode
|
|
||||||
if (s_monitor_enabled) {
|
if (s_monitor_enabled) {
|
||||||
ESP_LOGI(TAG, "Stopping monitor mode...");
|
ESP_LOGI(TAG, "Stopping monitor mode...");
|
||||||
wifi_monitor_stop();
|
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));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Set mode back to STA
|
|
||||||
ESP_LOGI(TAG, "Setting WiFi mode to STA...");
|
ESP_LOGI(TAG, "Setting WiFi mode to STA...");
|
||||||
esp_wifi_set_mode(WIFI_MODE_STA);
|
esp_wifi_set_mode(WIFI_MODE_STA);
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
// 4. Configure band preference
|
|
||||||
wifi_config_t wifi_config;
|
wifi_config_t wifi_config;
|
||||||
esp_wifi_get_config(WIFI_IF_STA, &wifi_config);
|
esp_wifi_get_config(WIFI_IF_STA, &wifi_config);
|
||||||
|
|
||||||
if (band_mode == WIFI_BAND_MODE_2G_ONLY) {
|
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;
|
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");
|
ESP_LOGI(TAG, "Configured for 2.4GHz band");
|
||||||
} else if (band_mode == WIFI_BAND_MODE_5G_ONLY) {
|
} 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;
|
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");
|
ESP_LOGI(TAG, "Configured for 5GHz band preference");
|
||||||
} else {
|
} else {
|
||||||
// Auto mode - let ESP-IDF choose best band
|
|
||||||
wifi_config.sta.channel = 0;
|
wifi_config.sta.channel = 0;
|
||||||
wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
|
wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
|
||||||
ESP_LOGI(TAG, "Configured for auto band selection");
|
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);
|
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
|
||||||
|
|
||||||
// 5. Start WiFi
|
|
||||||
ESP_LOGI(TAG, "Starting WiFi...");
|
ESP_LOGI(TAG, "Starting WiFi...");
|
||||||
esp_wifi_start();
|
esp_wifi_start();
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
// 6. Reconnect to AP
|
|
||||||
ESP_LOGI(TAG, "Connecting to AP...");
|
ESP_LOGI(TAG, "Connecting to AP...");
|
||||||
esp_wifi_connect();
|
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, " - CSI and iperf will start after connection");
|
||||||
ESP_LOGI(TAG, "========================================");
|
ESP_LOGI(TAG, "========================================");
|
||||||
|
|
||||||
// Note: CSI and iperf will be started by event handler when IP is obtained
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Console Commands ----------------------------------------------
|
// --- Console Commands ----------------------------------------------
|
||||||
|
|
||||||
static int cmd_mode_monitor(int argc, char **argv) {
|
static int cmd_mode_monitor(int argc, char **argv) {
|
||||||
int channel = monitor_channel; // Use last channel or default
|
int channel = monitor_channel;
|
||||||
wifi_bandwidth_t bandwidth = WIFI_BW_HT20; // Default to 20MHz
|
wifi_bandwidth_t bandwidth = WIFI_BW_HT20;
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
// Parse channel/bandwidth format: "6/20" or "36/40"
|
|
||||||
char *slash = strchr(argv[1], '/');
|
char *slash = strchr(argv[1], '/');
|
||||||
if (slash != NULL) {
|
if (slash != NULL) {
|
||||||
*slash = '\0'; // Split string at '/'
|
*slash = '\0';
|
||||||
channel = atoi(argv[1]);
|
channel = atoi(argv[1]);
|
||||||
int bw = atoi(slash + 1);
|
int bw = atoi(slash + 1);
|
||||||
|
|
||||||
// Convert bandwidth to enum - ESP32-C5 only supports 20/40MHz
|
|
||||||
switch(bw) {
|
switch(bw) {
|
||||||
case 20:
|
case 20: bandwidth = WIFI_BW_HT20; break;
|
||||||
bandwidth = WIFI_BW_HT20;
|
case 40: bandwidth = WIFI_BW_HT40; break;
|
||||||
break;
|
default: printf("Error: Invalid bandwidth %d\n", bw); return 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
channel = atoi(argv[1]);
|
channel = atoi(argv[1]);
|
||||||
// Monitor mode: always default to 20MHz (driver limitation)
|
|
||||||
bandwidth = WIFI_BW_HT20;
|
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;
|
bool valid = false;
|
||||||
const char* band = "Unknown";
|
if (channel >= 1 && channel <= 14) valid = true;
|
||||||
|
else if (channel >= 36 && channel <= 165) valid = true; // Simplified check
|
||||||
// 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 (!valid) {
|
if (!valid) {
|
||||||
printf("Error: Invalid channel %d\n", channel);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
printf("Monitoring channel %d\n", channel);
|
||||||
const char* bw_str = (bandwidth == WIFI_BW_HT40) ? "40MHz" : "20MHz";
|
|
||||||
|
|
||||||
printf("Monitoring channel %d (%s band, %s)\n", channel, band, bw_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t err = switch_to_monitor_mode(channel, bandwidth);
|
if (switch_to_monitor_mode(channel, bandwidth) != ESP_OK) {
|
||||||
if (err != ESP_OK) {
|
|
||||||
printf("Failed to switch to monitor mode\n");
|
printf("Failed to switch to monitor mode\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_mode_sta(int argc, char **argv) {
|
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 (argc > 1) {
|
||||||
if (strcmp(argv[1], "2.4") == 0 || strcmp(argv[1], "2") == 0) {
|
if (strcmp(argv[1], "2.4") == 0) band_mode = WIFI_BAND_MODE_2G_ONLY;
|
||||||
band_mode = WIFI_BAND_MODE_2G_ONLY;
|
else if (strcmp(argv[1], "5") == 0) band_mode = WIFI_BAND_MODE_5G_ONLY;
|
||||||
printf("Forcing 2.4GHz band\n");
|
else if (strcmp(argv[1], "auto") == 0) band_mode = WIFI_BAND_MODE_AUTO;
|
||||||
} else if (strcmp(argv[1], "5") == 0 || strcmp(argv[1], "5.0") == 0) {
|
else {
|
||||||
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 {
|
|
||||||
printf("Error: Invalid band '%s'\n", argv[1]);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t err = switch_to_sta_mode(band_mode);
|
if (switch_to_sta_mode(band_mode) != ESP_OK) {
|
||||||
if (err != ESP_OK) {
|
|
||||||
printf("Failed to switch to STA mode\n");
|
printf("Failed to switch to STA mode\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
printf("Switching to STA mode...\n");
|
||||||
printf("Switching to STA mode (reconnecting to AP...)\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -581,140 +481,62 @@ static int cmd_mode_status(int argc, char **argv) {
|
||||||
printf("\n=== WiFi Mode Status ===\n");
|
printf("\n=== WiFi Mode Status ===\n");
|
||||||
printf("Current mode: %s\n",
|
printf("Current mode: %s\n",
|
||||||
current_wifi_mode == WIFI_MODE_STA_CSI ? "STA (CSI + iperf)" : "MONITOR");
|
current_wifi_mode == WIFI_MODE_STA_CSI ? "STA (CSI + iperf)" : "MONITOR");
|
||||||
printf("LED state: ");
|
printf("LED state: %d\n", current_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current_wifi_mode == WIFI_MODE_STA_CSI) {
|
if (current_wifi_mode == WIFI_MODE_STA_CSI) {
|
||||||
printf("WiFi connected: %s\n", wifi_connected ? "Yes" : "No");
|
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");
|
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 {
|
} else {
|
||||||
const char* band = (monitor_channel >= 36) ? "5GHz" : "2.4GHz";
|
printf("Monitor channel: %d\n", monitor_channel);
|
||||||
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("Frames captured: %lu\n", (unsigned long)s_monitor_frame_count);
|
printf("Frames captured: %lu\n", (unsigned long)s_monitor_frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("GPS synced: %s\n", gps_is_synced() ? "Yes (+)" : "No (*)");
|
printf("GPS synced: %s\n", gps_is_synced() ? "Yes (+)" : "No (*)");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_csi_dump(int argc, char **argv) {
|
static int cmd_csi_dump(int argc, char **argv) {
|
||||||
if (current_wifi_mode != WIFI_MODE_STA_CSI) {
|
if (current_wifi_mode != WIFI_MODE_STA_CSI) {
|
||||||
printf("Error: CSI only available in STA mode\n");
|
printf("Error: CSI only available in STA mode\n");
|
||||||
printf("Use 'mode_sta' to switch to STA mode first\n");
|
|
||||||
return 1;
|
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");
|
printf("Dumping CSI data...\n");
|
||||||
csi_log_dump_over_uart();
|
csi_log_dump_over_uart();
|
||||||
printf("CSI dump complete\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_mode_commands(void) {
|
static void register_mode_commands(void) {
|
||||||
const esp_console_cmd_t mode_monitor = {
|
const esp_console_cmd_t mode_monitor = {
|
||||||
.command = "mode_monitor",
|
.command = "mode_monitor",
|
||||||
.help = "Switch to monitor mode (collapse detection)\n"
|
.help = "Switch to monitor mode",
|
||||||
" 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",
|
|
||||||
.func = &cmd_mode_monitor,
|
.func = &cmd_mode_monitor,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_monitor));
|
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_monitor));
|
||||||
|
|
||||||
const esp_console_cmd_t mode_sta = {
|
const esp_console_cmd_t mode_sta = {
|
||||||
.command = "mode_sta",
|
.command = "mode_sta",
|
||||||
.help = "Switch to STA mode (CSI + iperf)\n"
|
.help = "Switch to STA mode",
|
||||||
" 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",
|
|
||||||
.func = &cmd_mode_sta,
|
.func = &cmd_mode_sta,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_sta));
|
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_sta));
|
||||||
|
|
||||||
const esp_console_cmd_t mode_status = {
|
const esp_console_cmd_t mode_status = {
|
||||||
.command = "mode_status",
|
.command = "mode_status",
|
||||||
.help = "Show current WiFi mode and status",
|
.help = "Show status",
|
||||||
.func = &cmd_mode_status,
|
.func = &cmd_mode_status,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_status));
|
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_status));
|
||||||
|
|
||||||
const esp_console_cmd_t csi_dump = {
|
const esp_console_cmd_t csi_dump = {
|
||||||
.command = "csi_dump",
|
.command = "csi_dump",
|
||||||
.help = "Dump CSI data to UART (STA mode only)",
|
.help = "Dump CSI data",
|
||||||
.func = &cmd_csi_dump,
|
.func = &cmd_csi_dump,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(esp_console_cmd_register(&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,
|
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||||
int32_t event_id, void* event_data) {
|
int32_t event_id, void* event_data) {
|
||||||
if (event_base == WIFI_EVENT) {
|
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) {
|
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||||
if (current_wifi_mode != WIFI_MODE_STA_CSI) {
|
if (current_wifi_mode != WIFI_MODE_STA_CSI) return;
|
||||||
ESP_LOGW(TAG, "Got IP but not in STA mode (mode changed during connection)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
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, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
|
||||||
ESP_LOGI(TAG, "========================================");
|
|
||||||
|
|
||||||
wifi_connected = true;
|
wifi_connected = true;
|
||||||
current_led_state = LED_STATE_CONNECTED;
|
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...");
|
ESP_LOGI(TAG, "Enabling CSI...");
|
||||||
wifi_enable_csi_once();
|
wifi_enable_csi_once();
|
||||||
|
|
||||||
// 2. Start iperf server
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
iperf_cfg_t cfg;
|
iperf_cfg_t cfg;
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
cfg.flag = IPERF_FLAG_SERVER | IPERF_FLAG_TCP;
|
cfg.flag = IPERF_FLAG_SERVER | IPERF_FLAG_TCP;
|
||||||
cfg.sport = 5001;
|
cfg.sport = 5001;
|
||||||
iperf_start(&cfg);
|
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);
|
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) {
|
void app_main(void) {
|
||||||
// 1. Initialize Non-Volatile Storage (needed for WiFi config)
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_init());
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
|
|
||||||
// 2. Initialize Netif (TCP/IP stack)
|
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
// 3. Initialize Custom Logging & LED
|
// Init Logging & LED
|
||||||
ESP_ERROR_CHECK(csi_log_init());
|
ESP_ERROR_CHECK(csi_log_init());
|
||||||
rgb_led_init();
|
rgb_led_init();
|
||||||
xTaskCreate(led_task, "led_task", 4096, NULL, 5, NULL);
|
xTaskCreate(led_task, "led_task", 4096, NULL, 5, NULL);
|
||||||
|
|
||||||
// 4. Initialize GPS (Enable GPS-timestamped logs)
|
// Init GPS
|
||||||
ESP_LOGI(TAG, "========================================");
|
|
||||||
ESP_LOGI(TAG, "Initializing GPS sync...");
|
ESP_LOGI(TAG, "Initializing GPS sync...");
|
||||||
|
|
||||||
// CONFIGURATION STRUCT: Maps the correct pins based on the chip type
|
|
||||||
const gps_sync_config_t gps_cfg = {
|
const gps_sync_config_t gps_cfg = {
|
||||||
.uart_port = UART_NUM_1,
|
.uart_port = UART_NUM_1,
|
||||||
.tx_pin = GPS_TX_PIN,
|
.tx_pin = GPS_TX_PIN,
|
||||||
.rx_pin = GPS_RX_PIN,
|
.rx_pin = GPS_RX_PIN,
|
||||||
.pps_pin = GPS_PPS_PIN,
|
.pps_pin = GPS_PPS_PIN,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pass the config and enable GPS timestamps in logs
|
|
||||||
gps_sync_init(&gps_cfg, true);
|
gps_sync_init(&gps_cfg, true);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "GPS initialized on UART1 (TX:%d, RX:%d, PPS:%d)",
|
ESP_LOGI(TAG, "GPS init (TX:%d, RX:%d, PPS:%d)", GPS_TX_PIN, GPS_RX_PIN, GPS_PPS_PIN);
|
||||||
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, "========================================");
|
|
||||||
|
|
||||||
// 5. Register WiFi Events
|
// Register Events
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, NULL));
|
||||||
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));
|
||||||
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();
|
wifi_cfg_init();
|
||||||
|
|
||||||
// 7. Initialize Serial Console (CRITICAL for console commands)
|
// Init Console
|
||||||
ESP_LOGI(TAG, "Initializing console...");
|
ESP_LOGI(TAG, "Initializing console...");
|
||||||
|
|
||||||
/* Disable buffering on stdin */
|
|
||||||
setvbuf(stdin, NULL, _IONBF, 0);
|
setvbuf(stdin, NULL, _IONBF, 0);
|
||||||
|
|
||||||
/* Initialize the console */
|
|
||||||
esp_console_config_t console_config = {
|
esp_console_config_t console_config = {
|
||||||
.max_cmdline_args = 8,
|
.max_cmdline_args = 8,
|
||||||
.max_cmdline_length = 256,
|
.max_cmdline_length = 256,
|
||||||
|
|
@ -837,90 +619,51 @@ void app_main(void) {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(esp_console_init(&console_config));
|
ESP_ERROR_CHECK(esp_console_init(&console_config));
|
||||||
|
|
||||||
/* Configure linenoise line completion library */
|
|
||||||
linenoiseSetMultiLine(1);
|
linenoiseSetMultiLine(1);
|
||||||
linenoiseSetCompletionCallback(NULL);
|
linenoiseSetCompletionCallback(NULL);
|
||||||
linenoiseSetHintsCallback(NULL);
|
linenoiseSetHintsCallback(NULL);
|
||||||
linenoiseHistorySetMaxLen(100);
|
linenoiseHistorySetMaxLen(100);
|
||||||
|
|
||||||
/* Register help command */
|
|
||||||
esp_console_register_help_command();
|
esp_console_register_help_command();
|
||||||
|
|
||||||
ESP_LOGI(TAG, "✓ Console initialized");
|
|
||||||
|
|
||||||
// 8. Register Console Commands for Mode Switching
|
|
||||||
register_mode_commands();
|
register_mode_commands();
|
||||||
|
|
||||||
// 9. Apply WiFi config and connect
|
// Apply Config
|
||||||
if (wifi_cfg_apply_from_nvs()) {
|
if (wifi_cfg_apply_from_nvs()) {
|
||||||
has_config = true;
|
has_config = true;
|
||||||
current_led_state = LED_STATE_WAITING;
|
current_led_state = LED_STATE_WAITING;
|
||||||
ESP_LOGI(TAG, "========================================");
|
ESP_LOGI(TAG, "WiFi config loaded.");
|
||||||
ESP_LOGI(TAG, "WiFi config loaded. Connecting...");
|
|
||||||
|
|
||||||
// Check if device is configured for MONITOR mode
|
|
||||||
char mode[16] = {0};
|
char mode[16] = {0};
|
||||||
uint8_t mon_ch = 36;
|
uint8_t mon_ch = 36;
|
||||||
if (wifi_cfg_get_mode(mode, &mon_ch)) {
|
if (wifi_cfg_get_mode(mode, &mon_ch)) {
|
||||||
if (strcmp(mode, "MONITOR") == 0) {
|
if (strcmp(mode, "MONITOR") == 0) {
|
||||||
ESP_LOGI(TAG, "MODE: MONITOR (collapse detection)");
|
ESP_LOGI(TAG, "MODE: MONITOR (Channel %d)", mon_ch);
|
||||||
ESP_LOGI(TAG, "Monitor Channel: %d", mon_ch);
|
|
||||||
ESP_LOGI(TAG, "Will switch to monitor mode after WiFi connects...");
|
|
||||||
|
|
||||||
// Allocate channel parameter for task
|
|
||||||
uint8_t *ch_param = malloc(sizeof(uint8_t));
|
uint8_t *ch_param = malloc(sizeof(uint8_t));
|
||||||
*ch_param = mon_ch;
|
*ch_param = mon_ch;
|
||||||
|
|
||||||
// Create task to switch to monitor mode after connection
|
|
||||||
xTaskCreate(auto_monitor_task, "auto_monitor", 4096, ch_param, 5, NULL);
|
xTaskCreate(auto_monitor_task, "auto_monitor", 4096, ch_param, 5, NULL);
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
has_config = false;
|
has_config = false;
|
||||||
current_led_state = LED_STATE_NO_CONFIG;
|
current_led_state = LED_STATE_NO_CONFIG;
|
||||||
ESP_LOGI(TAG, "========================================");
|
|
||||||
ESP_LOGI(TAG, "No WiFi config found.");
|
ESP_LOGI(TAG, "No WiFi config found.");
|
||||||
ESP_LOGI(TAG, "LED: Yellow");
|
|
||||||
ESP_LOGI(TAG, "Use CLI command: wifi_config_set <ssid> <pass>");
|
|
||||||
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) {
|
static void auto_monitor_task(void *arg) {
|
||||||
uint8_t channel = *(uint8_t*)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...");
|
ESP_LOGI(TAG, "Waiting for WiFi connection before switching to monitor mode...");
|
||||||
while (current_led_state != LED_STATE_CONNECTED) {
|
while (current_led_state != LED_STATE_CONNECTED) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait additional 2 seconds for GPS sync
|
|
||||||
ESP_LOGI(TAG, "WiFi connected, waiting for GPS sync...");
|
ESP_LOGI(TAG, "WiFi connected, waiting for GPS sync...");
|
||||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Auto-switching to MONITOR mode on channel %d...", channel);
|
ESP_LOGI(TAG, "Auto-switching to MONITOR mode on channel %d...", channel);
|
||||||
esp_err_t err = switch_to_monitor_mode(channel, WIFI_BW_HT20);
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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"
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue