diff --git a/firmware/esp32-csi-node/main/adaptive_controller.c b/firmware/esp32-csi-node/main/adaptive_controller.c index f85a22b924..e73a19dbf9 100644 --- a/firmware/esp32-csi-node/main/adaptive_controller.c +++ b/firmware/esp32-csi-node/main/adaptive_controller.c @@ -225,7 +225,7 @@ static void fast_loop_cb(TimerHandle_t t) * the default 200 ms fast period), which combined with CSI promiscuous * RX saturated the WiFi TX airtime — measured live on COM8 (S3) and * COM9 (C6): every adaptive cycle showed `sendto ENOMEM — backing off - * for 100 ms`, and bumping LWIP/WiFi buffer pools to 4× had no effect + * for the ENOMEM cooldown`, and bumping LWIP/WiFi buffer pools to 4× had no effect * on the rate because the bottleneck was radio TX time, not pool size. * Dropping to 1 Hz (5× less feature_state traffic) frees the TX queue * for CSI sends and lands well within the spec. */ diff --git a/firmware/esp32-csi-node/main/csi_collector.c b/firmware/esp32-csi-node/main/csi_collector.c index 0dc03676d8..5f2c44a80e 100644 --- a/firmware/esp32-csi-node/main/csi_collector.c +++ b/firmware/esp32-csi-node/main/csi_collector.c @@ -376,7 +376,7 @@ static void wifi_promiscuous_cb(void *buf, wifi_promiscuous_pkt_type_t type) * are sparse beacons (often non-OFDM DSSS), so wifi_csi_callback can starve to * yield=0pps -> DEGRADED -> motion/presence=0 (#521, #954). * - * This guarantees a ~50 Hz OFDM unicast floor by pinging the STA's own gateway: + * This guarantees a ~10 Hz OFDM unicast floor by pinging the STA's own gateway: * the router's ICMP echo replies are OFDM frames destined to this station, which * drive the CSI engine regardless of promiscuous filter state or ambient traffic. * It is ADDITIVE — promiscuous capture (#396/#893) is left fully intact so @@ -409,7 +409,9 @@ static void csi_start_self_ping(void) esp_ping_config_t cfg = ESP_PING_DEFAULT_CONFIG(); cfg.target_addr = target; cfg.count = ESP_PING_COUNT_INFINITE; - cfg.interval_ms = 20; /* 50 Hz -> ~50 received OFDM replies/sec */ + cfg.interval_ms = 100; /* 10 Hz: cut self-ping TX flood that exhausts + S3 WiFi TX buffers -> sendto ENOMEM (#1135). + 10 Hz still keeps the CSI OFDM source alive. */ cfg.data_size = 1; cfg.task_stack_size = 4096; @@ -422,7 +424,7 @@ static void csi_start_self_ping(void) if (esp_ping_new_session(&cfg, &cbs, &s_self_ping) == ESP_OK && s_self_ping != NULL) { esp_ping_start(s_self_ping); - ESP_LOGI(TAG, "self-ping started -> %s @50Hz (CSI OFDM source, fix #521/#954)", gw_str); + ESP_LOGI(TAG, "self-ping started -> %s @10Hz (CSI OFDM source, fix #521/#954, S3 ENOMEM #1135)", gw_str); } else { ESP_LOGW(TAG, "self-ping: esp_ping_new_session failed"); s_self_ping = NULL; diff --git a/firmware/esp32-csi-node/main/stream_sender.c b/firmware/esp32-csi-node/main/stream_sender.c index b85c206a59..7819b1aba4 100644 --- a/firmware/esp32-csi-node/main/stream_sender.c +++ b/firmware/esp32-csi-node/main/stream_sender.c @@ -26,7 +26,8 @@ static struct sockaddr_in s_dest_addr; * rapid-fire CSI callbacks can exhaust the pbuf pool and crash the device. */ static int64_t s_backoff_until_us = 0; /* esp_timer timestamp to resume */ -#define ENOMEM_COOLDOWN_MS 100 /* suppress sends for 100 ms */ +#define ENOMEM_COOLDOWN_MS 300 /* suppress sends for 300 ms — 100 ms + * was too short to drain on S3 (#1135) */ #define ENOMEM_LOG_INTERVAL 50 /* log every Nth suppressed send */ static uint32_t s_enomem_suppressed = 0; diff --git a/firmware/esp32-csi-node/sdkconfig.defaults b/firmware/esp32-csi-node/sdkconfig.defaults index 94ec09222a..d196dd121a 100644 --- a/firmware/esp32-csi-node/sdkconfig.defaults +++ b/firmware/esp32-csi-node/sdkconfig.defaults @@ -41,7 +41,7 @@ CONFIG_LWIP_SO_RCVBUF=y # ~3 KB extra heap cost, measured live on both targets Jun 8 2026. CONFIG_LWIP_UDP_RECVMBOX_SIZE=32 CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64 -CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64 +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=128 # NOTE: Empirical 25 s measurements on the S3 at COM8 showed these bumps # eliminate the csi_collector.sendto failure path (`fail #1..5` → # `fail #0`) — real improvement — but do NOT eliminate the broader diff --git a/firmware/esp32-csi-node/sdkconfig.defaults.esp32c6 b/firmware/esp32-csi-node/sdkconfig.defaults.esp32c6 index b6bda708e5..919457450d 100644 --- a/firmware/esp32-csi-node/sdkconfig.defaults.esp32c6 +++ b/firmware/esp32-csi-node/sdkconfig.defaults.esp32c6 @@ -70,6 +70,13 @@ CONFIG_LWIP_SO_RCVBUF=y CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=8192 +# ── Wi-Fi dynamic TX buffers: pin to the C6's verified value ── +# The S3 ENOMEM fix (#1135) raises CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM to 128 +# in the base sdkconfig.defaults. That fix was hardware-verified on the S3 only, +# so keep the C6 build at its previously-shipping 64 rather than silently +# inheriting 128 on an untested target. Re-tune here if the C6 ever needs it. +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64 + # ── Power: keep CPU at max 160 MHz (C6 ceiling) for DSP throughput ── CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160