From dc63a992f3d0079b2e17c3f7e22e14ad75533410 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 20 Nov 2025 18:20:44 -0800 Subject: [PATCH] csi support compiles for c5 --- components/csi_log/CMakeLists.txt | 5 + components/csi_log/csi_log.c | 179 ++++++++++++++++++++++++++++++ components/csi_log/csi_log.h | 19 ++++ components/wifi_cfg/wifi_cfg.c | 16 ++- main/CMakeLists.txt | 2 +- main/main.c | 101 +++++++++++++---- main/wifi_cfg.c | 161 --------------------------- main/wifi_cfg.h | 15 --- 8 files changed, 298 insertions(+), 200 deletions(-) create mode 100644 components/csi_log/CMakeLists.txt create mode 100644 components/csi_log/csi_log.c create mode 100644 components/csi_log/csi_log.h delete mode 100644 main/wifi_cfg.c delete mode 100644 main/wifi_cfg.h diff --git a/components/csi_log/CMakeLists.txt b/components/csi_log/CMakeLists.txt new file mode 100644 index 0000000..8eced1d --- /dev/null +++ b/components/csi_log/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS "csi_log.c" + INCLUDE_DIRS "." + REQUIRES esp_wifi esp_partition +) diff --git a/components/csi_log/csi_log.c b/components/csi_log/csi_log.c new file mode 100644 index 0000000..765533f --- /dev/null +++ b/components/csi_log/csi_log.c @@ -0,0 +1,179 @@ +#include "csi_log.h" + +#include +#include +#include + +#include "esp_partition.h" +#include "esp_log.h" + +static const char *TAG = "csi_log"; + +typedef struct __attribute__((packed)) { + uint32_t seq; + int32_t ts_us; + int8_t rssi; + uint8_t reserved; + uint16_t len; // CSI payload length in bytes +} csi_record_hdr_t; + +static const esp_partition_t *s_csi_part = NULL; +static size_t s_csi_offset = 0; // bytes written this run +static uint32_t s_csi_seq = 0; + +esp_err_t csi_log_init(void) +{ + s_csi_part = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, + 0x40, // subtype from partitions.csv + "csi_log"); + + if (!s_csi_part) { + ESP_LOGE(TAG, "csi_log partition not found"); + return ESP_ERR_NOT_FOUND; + } + + ESP_LOGI(TAG, "csi_log size=%u bytes, addr=0x%08x", + (unsigned)s_csi_part->size, + (unsigned)s_csi_part->address); + + // Erase once per experiment + esp_err_t err = esp_partition_erase_range( + s_csi_part, + 0, + s_csi_part->size); + if (err != ESP_OK) { + ESP_LOGE(TAG, "erase failed: %s", esp_err_to_name(err)); + s_csi_part = NULL; + return err; + } + + s_csi_offset = 0; + s_csi_seq = 0; + return ESP_OK; +} + +void csi_log_append_record(const wifi_csi_info_t *info) +{ + if (!s_csi_part || !info) { + return; + } + + // Basic sanity bounds + if (info->len == 0 || info->len > 512) { + return; + } + + csi_record_hdr_t hdr = { + .seq = s_csi_seq++, + .ts_us = (int32_t)info->rx_ctrl.timestamp, + .rssi = info->rx_ctrl.rssi, + .reserved = 0, + .len = info->len, + }; + + uint16_t rec_bytes = sizeof(hdr) + info->len; + size_t needed = s_csi_offset + 2 /*len field*/ + rec_bytes; + + if (needed > s_csi_part->size) { + static bool warned = false; + if (!warned) { + ESP_LOGW(TAG, "csi_log full, dropping subsequent records"); + warned = true; + } + return; + } + + esp_err_t err; + + // Write record length (header+payload) + err = esp_partition_write(s_csi_part, s_csi_offset, + &rec_bytes, sizeof(rec_bytes)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "write rec_len failed: %s", esp_err_to_name(err)); + return; + } + s_csi_offset += sizeof(rec_bytes); + + // Write header + err = esp_partition_write(s_csi_part, s_csi_offset, + &hdr, sizeof(hdr)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "write hdr failed: %s", esp_err_to_name(err)); + return; + } + s_csi_offset += sizeof(hdr); + + // Write payload + err = esp_partition_write(s_csi_part, s_csi_offset, + info->buf, info->len); + if (err != ESP_OK) { + ESP_LOGE(TAG, "write payload failed: %s", esp_err_to_name(err)); + return; + } + s_csi_offset += info->len; +} + +void csi_log_dump_over_uart(void) +{ + if (!s_csi_part) { + printf("CSI_DUMP_ERROR no_partition\n"); + return; + } + + printf("CSI_DUMP_BEGIN %u\n", (unsigned)s_csi_offset); + + size_t pos = 0; + while (pos + 2 <= s_csi_offset) { + uint16_t rec_bytes = 0; + esp_err_t err = esp_partition_read( + s_csi_part, pos, &rec_bytes, sizeof(rec_bytes)); + if (err != ESP_OK) { + printf("CSI_DUMP_ERROR read_len %s\n", esp_err_to_name(err)); + break; + } + pos += sizeof(rec_bytes); + + if (rec_bytes < sizeof(csi_record_hdr_t) || + pos + rec_bytes > s_csi_offset) { + break; + } + + csi_record_hdr_t hdr; + err = esp_partition_read( + s_csi_part, pos, &hdr, sizeof(hdr)); + if (err != ESP_OK) { + printf("CSI_DUMP_ERROR read_hdr %s\n", esp_err_to_name(err)); + break; + } + pos += sizeof(hdr); + + uint16_t csi_len = hdr.len; + if (csi_len > rec_bytes - sizeof(hdr)) { + break; + } + + static uint8_t buf[512]; + if (csi_len > sizeof(buf)) { + csi_len = sizeof(buf); + } + + err = esp_partition_read( + s_csi_part, pos, buf, csi_len); + if (err != ESP_OK) { + printf("CSI_DUMP_ERROR read_csi %s\n", esp_err_to_name(err)); + break; + } + pos += (rec_bytes - sizeof(hdr)); // skip to record boundary + + // Text record line + printf("R %" PRIu32 " %" PRId32 " %d %u ", + hdr.seq, hdr.ts_us, hdr.rssi, (unsigned)csi_len); + for (int i = 0; i < csi_len; i++) { + printf("%02X", buf[i]); + } + printf("\n"); + } + + printf("CSI_DUMP_END\n"); +} diff --git a/components/csi_log/csi_log.h b/components/csi_log/csi_log.h new file mode 100644 index 0000000..1088b5f --- /dev/null +++ b/components/csi_log/csi_log.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "esp_err.h" +#include "esp_wifi.h" // wifi_csi_info_t + +// Initialize CSI log partition and erase it once per run. +esp_err_t csi_log_init(void); + +// Append one CSI record to flash (header + CSI payload). +void csi_log_append_record(const wifi_csi_info_t *info); + +// Dump all logged records as text lines over UART. +// Format: +// CSI_DUMP_BEGIN +// R +// ... +// CSI_DUMP_END +void csi_log_dump_over_uart(void); diff --git a/components/wifi_cfg/wifi_cfg.c b/components/wifi_cfg/wifi_cfg.c index edfe8cc..009801e 100644 --- a/components/wifi_cfg/wifi_cfg.c +++ b/components/wifi_cfg/wifi_cfg.c @@ -149,6 +149,14 @@ bool wifi_cfg_apply_from_nvs(void) { ESP_LOGW(TAG, "No Wi‑Fi config in NVS"); return false; } + // Treat empty SSID as "no config" to avoid ESP_ERR_WIFI_SSID panics + 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 Band=%s BW=%s", + ssid, dhcp, ip, band, bw); + ESP_LOGI(TAG, "Applying Wi‑Fi config: SSID=%s DHCP=%d IP=%s Band=%s BW=%s", ssid, dhcp, ip, band, bw); static bool inited = false; @@ -198,15 +206,15 @@ bool wifi_cfg_apply_from_nvs(void) { } ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); - // Enable WiFi 6 (802.11ax) and all protocols for best compatibility wifi_protocols_t protocols = { // 2.4 GHz: b/g/n/ax .ghz_2g = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | - WIFI_PROTOCOL_11N | - WIFI_PROTOCOL_11AX, - + WIFI_PROTOCOL_11N, + // Restrict protocols so CSI can work: + // - CSI on ESP32-C5 is only supported on 2.4 GHz HT (11n), not HE (11ax) + // WIFI_PROTOCOL_11AX, // 5 GHz: a/n/ac/ax .ghz_5g = WIFI_PROTOCOL_11A | WIFI_PROTOCOL_11N | diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 4aa8685..3f8b032 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "main.c" INCLUDE_DIRS "." - REQUIRES led_strip driver) + REQUIRES led_strip driver wifi_cfg csi_log esp_wifi esp_netif nvs_flash) diff --git a/main/main.c b/main/main.c index e01384c..60a456c 100644 --- a/main/main.c +++ b/main/main.c @@ -19,6 +19,8 @@ #include "iperf.h" #include "wifi_cfg.h" +#include "csi_log.h" + static const char *TAG = "main"; @@ -123,28 +125,80 @@ static void led_task(void *arg) } } +// --- CSI support --------------------------------------------------- +static bool s_csi_enabled = false; + +static void csi_dump_task(void *arg) { + // Wait some time to accumulate CSI records, then dump them over UART + vTaskDelay(pdMS_TO_TICKS(20000)); + csi_log_dump_over_uart(); + vTaskDelete(NULL); +} + +static void csi_cb(void *ctx, wifi_csi_info_t *info) +{ + // Just log to flash; no heavy work here + csi_log_append_record(info); +} + +static void wifi_enable_csi_once(void) +{ + if (s_csi_enabled) { + return; + } + + // On your C5 + IDF, wifi_csi_config_t only has `.enable` + wifi_csi_config_t csi_cfg = { + .enable = true, + }; + + esp_err_t err; + + err = esp_wifi_set_csi_config(&csi_cfg); + if (err != ESP_OK) { + ESP_LOGW("CSI", "esp_wifi_set_csi_config failed: %s", esp_err_to_name(err)); + return; + } + + err = esp_wifi_set_csi_rx_cb(csi_cb, NULL); + if (err != ESP_OK) { + ESP_LOGW("CSI", "esp_wifi_set_csi_rx_cb failed: %s", esp_err_to_name(err)); + return; + } + + err = esp_wifi_set_csi(true); + if (err != ESP_OK) { + ESP_LOGW("CSI", "esp_wifi_set_csi(true) failed: %s", esp_err_to_name(err)); + return; + } + + ESP_LOGI("CSI", "CSI enabled"); + s_csi_enabled = true; +} + static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_base == WIFI_EVENT) { switch (event_id) { - case WIFI_EVENT_STA_START: - ESP_LOGI(TAG, "WiFi started, attempting connection..."); - if (has_config) { - current_led_state = LED_STATE_WAITING; - } - break; + case WIFI_EVENT_STA_START: + ESP_LOGI(TAG, "WiFi started, attempting connection..."); + if (has_config) { + current_led_state = LED_STATE_WAITING; + } + break; - case WIFI_EVENT_STA_DISCONNECTED: - wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data; - ESP_LOGW(TAG, "WiFi disconnected, reason: %d", event->reason); + case WIFI_EVENT_STA_DISCONNECTED: + wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data; + ESP_LOGW(TAG, "WiFi disconnected, reason: %d", event->reason); - if (!wifi_connected && has_config) { - current_led_state = LED_STATE_FAILED; - ESP_LOGE(TAG, "WiFi connection FAILED - RED LED blinking"); - } - break; + if (!wifi_connected && has_config) { + current_led_state = LED_STATE_FAILED; + ESP_LOGE(TAG, "WiFi connection FAILED - RED LED blinking"); + } + break; } + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; ESP_LOGI(TAG, "got ip:" IPSTR " gw:" IPSTR " netmask:" IPSTR, @@ -156,6 +210,9 @@ static void event_handler(void* arg, esp_event_base_t event_base, current_led_state = LED_STATE_CONNECTED; ESP_LOGI(TAG, "WiFi CONNECTED - BLUE LED solid"); + // Enable CSI once we know Wi-Fi is fully up + wifi_enable_csi_once(); + // Auto-start iperf server vTaskDelay(pdMS_TO_TICKS(1000)); @@ -166,15 +223,21 @@ static void event_handler(void* arg, esp_event_base_t event_base, iperf_start(&cfg); ESP_LOGI(TAG, "iperf TCP server started on port 5001"); + + // Schedule CSI dump after 20 seconds of capture + BaseType_t task_ok = xTaskCreate(csi_dump_task, "csi_dump_task", 4096, NULL, 5, NULL); + if (task_ok != pdPASS) { + ESP_LOGE("CSI", "Failed to create csi_dump_task"); + } } } -void app_main(void) -{ +void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); - + // Initialize CSI flash logging + ESP_ERROR_CHECK(csi_log_init()); // Initialize RGB LED rgb_led_init(); @@ -183,9 +246,9 @@ void app_main(void) // Register WiFi events 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)); + IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, NULL)); // Initialize WiFi config wifi_cfg_init(); diff --git a/main/wifi_cfg.c b/main/wifi_cfg.c deleted file mode 100644 index ba44ecc..0000000 --- a/main/wifi_cfg.c +++ /dev/null @@ -1,161 +0,0 @@ - -#include -#include -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_system.h" -#include "esp_log.h" -#include "nvs_flash.h" -#include "nvs.h" -#include "esp_netif.h" -#include "esp_wifi.h" -#include "esp_event.h" -#include "driver/uart.h" -#include "esp_vfs_dev.h" -#include "driver/usb_serial_jtag.h" -#include "esp_vfs_usb_serial_jtag.h" - -static const char *TAG = "wifi_cfg"; - -static void trim(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; - 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){ - return val ? nvs_set_str(h, key, val) : nvs_erase_key(h, key); -} - -static bool cfg_dhcp = true; - -static void save_cfg(const char* ssid, const char* pass, const char* ip, const char* mask, const char* gw, bool dhcp){ - nvs_handle_t h; - if (nvs_open("netcfg", NVS_READWRITE, &h) != ESP_OK) return; - if (ssid) nvs_set_str2(h, "ssid", ssid); - if (pass) nvs_set_str2(h, "pass", pass); - if (ip) nvs_set_str2(h, "ip", ip); - if (mask) nvs_set_str2(h, "mask", mask); - if (gw) nvs_set_str2(h, "gw", gw); - nvs_set_u8(h, "dhcp", dhcp ? 1 : 0); - nvs_commit(h); - nvs_close(h); - cfg_dhcp = dhcp; -} - -static bool load_cfg(char* ssid, size_t ssz, char* pass, size_t psz, char* ip, size_t isz, char* mask, size_t msz, char* gw, size_t gsz, bool* dhcp){ - nvs_handle_t h; - if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) return false; - size_t len; - esp_err_t e; - if ((e = nvs_get_str(h, "ssid", NULL, &len)) != ESP_OK){ nvs_close(h); return false; } - if (len >= ssz){ nvs_close(h); return false; } - nvs_get_str(h, "ssid", ssid, &len); - len = psz; e = nvs_get_str(h, "pass", pass, &len); if (e!=ESP_OK) pass[0]=0; - len = isz; e = nvs_get_str(h, "ip", ip, &len); if (e!=ESP_OK) ip[0]=0; - len = msz; e = nvs_get_str(h, "mask", mask, &len); if (e!=ESP_OK) mask[0]=0; - len = gsz; e = nvs_get_str(h, "gw", gw, &len); if (e!=ESP_OK) gw[0]=0; - uint8_t d=1; nvs_get_u8(h, "dhcp", &d); *dhcp = (d!=0); - nvs_close(h); - return true; -} - -void wifi_cfg_force_dhcp(bool enable){ cfg_dhcp = enable; } - -static esp_netif_t *sta_netif = NULL; - -static void apply_ip_static(const char* ip, const char* mask, const char* gw){ - if (!sta_netif) return; - esp_netif_ip_info_t info = {0}; - esp_netif_dhcpc_stop(sta_netif); - esp_ip4addr_aton(ip, &info.ip.addr); - esp_ip4addr_aton(mask, &info.netmask.addr); - esp_ip4addr_aton(gw, &info.gw.addr); - ESP_ERROR_CHECK( esp_netif_set_ip_info(sta_netif, &info) ); -} - -bool wifi_cfg_apply_from_nvs(void){ - char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0}; - bool dhcp = true; - if (!load_cfg(ssid,sizeof(ssid), pass,sizeof(pass), ip,sizeof(ip), mask,sizeof(mask), gw,sizeof(gw), &dhcp)){ - ESP_LOGW(TAG, "No Wi‑Fi config in NVS"); - return false; - } - ESP_LOGI(TAG, "Applying Wi‑Fi config: SSID=%s DHCP=%d IP=%s", ssid, dhcp, ip); - - static bool inited = false; - if (!inited){ - ESP_ERROR_CHECK(nvs_flash_init()); - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - sta_netif = esp_netif_create_default_wifi_sta(); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); - inited = true; - } - - wifi_config_t wcfg = {0}; - strncpy((char*)wcfg.sta.ssid, ssid, sizeof(wcfg.sta.ssid)-1); - strncpy((char*)wcfg.sta.password, pass, sizeof(wcfg.sta.password)-1); - wcfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; - wcfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH; - ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wcfg) ); - - if (!dhcp && ip[0] && mask[0] && gw[0]){ - apply_ip_static(ip, mask, gw); - }else{ - if (sta_netif) esp_netif_dhcpc_start(sta_netif); - } - - ESP_ERROR_CHECK( esp_wifi_start() ); - ESP_ERROR_CHECK( esp_wifi_connect() ); - return true; -} - -static void cfg_listener_task(void *arg){ - esp_vfs_usb_serial_jtag_use_driver(); - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); - - char line[160]; - char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0}; - bool dhcp = true; - bool in_cfg = false; - - while (1){ - if (!fgets(line, sizeof(line), stdin)){ - vTaskDelay(pdMS_TO_TICKS(50)); - continue; - } - trim(line); - if (!in_cfg){ - if (strcmp(line, "CFG")==0){ - in_cfg = true; - ssid[0]=pass[0]=ip[0]=mask[0]=gw[0]=0; - dhcp = true; - } - continue; - } - if (strcmp(line, "END")==0){ - save_cfg(ssid, pass, ip, mask, gw, dhcp); - printf("OK\n"); - wifi_cfg_apply_from_nvs(); - in_cfg = false; - continue; - } - if (strncmp(line, "SSID:",5)==0){ strncpy(ssid, line+5, sizeof(ssid)-1); continue; } - if (strncmp(line, "PASS:",5)==0){ strncpy(pass, line+5, sizeof(pass)-1); continue; } - if (strncmp(line, "IP:",3)==0){ strncpy(ip, line+3, sizeof(ip)-1); continue; } - if (strncmp(line, "MASK:",5)==0){ strncpy(mask, line+5, sizeof(mask)-1); continue; } - if (strncmp(line, "GW:",3)==0){ strncpy(gw, line+3, sizeof(gw)-1); continue; } - if (strncmp(line, "DHCP:",5)==0){ dhcp = atoi(line+5) ? true:false; continue; } - } -} - -void wifi_cfg_init(void){ - nvs_flash_init(); - xTaskCreatePinnedToCore(cfg_listener_task, "cfg_listener", 4096, NULL, 5, NULL, tskNO_AFFINITY); -} diff --git a/main/wifi_cfg.h b/main/wifi_cfg.h deleted file mode 100644 index 3782d72..0000000 --- a/main/wifi_cfg.h +++ /dev/null @@ -1,15 +0,0 @@ - -#pragma once -#ifdef __cplusplus -extern "C" { -#endif - -#include - -void wifi_cfg_init(void); // starts serial listener task -bool wifi_cfg_apply_from_nvs(void); // reads saved config and connects Wi‑Fi -void wifi_cfg_force_dhcp(bool enable); // for testing - -#ifdef __cplusplus -} -#endif