fix(esp32): make CSI callback actually fire (connected-STA CSI + self-ping)#955
fix(esp32): make CSI callback actually fire (connected-STA CSI + self-ping)#955merajmehrabi wants to merge 1 commit into
Conversation
…-ping) The ESP32 CSI engine only produces CSI for received OFDM frames (L-LTF/ HT-LTF). csi_collector_init() captured CSI only via a MGMT-only promiscuous filter (the ruvnet#396 Core-0 DATA-sniff crash workaround), so the only CSI-eligible frames were beacons -- which APs transmit at non-OFDM DSSS rates carrying no training field. Result: wifi_csi_callback never fired, pkt_yield=0pps, adaptive controller stuck in DEGRADED, motion/presence=0 (ruvnet#521, ruvnet#954). The probe/NDP "injection" in the comments is an uncalled TX-only stub, and the prior ruvnet#521 fix (esp_wifi_set_ps(WIFI_PS_NONE)) was committed without hardware verification and does not resolve it. Fix: mirror Espressif's esp-csi csi_recv_router reference -- disable promiscuous mode and ping the gateway at 50 Hz so received OFDM replies drive the CSI engine. Running without promiscuous also sidesteps the ruvnet#396 Core-0 DATA-sniff crash entirely. Verified on ESP32-S3 (N16R8), ESP-IDF v5.4: CSI cb fires, yield ~30 pps, adaptive state -> SENSE_ACTIVE, DEGRADED cleared, breathing + heart rate computed with PRES/RESP/HB_VALID flags set. Closes ruvnet#954. Supersedes the unverified ruvnet#521 fix. Co-Authored-By: claude-flow <ruv@ruv.net>
The ESP32 CSI engine only produces CSI for received OFDM frames (L-LTF/ HT-LTF). On a quiet network — or on a display-enabled build where the #893 MGMT->MGMT+DATA promiscuous upgrade is skipped (has_display=true) — the only CSI-eligible frames are sparse beacons (often non-OFDM DSSS), so wifi_csi_callback can starve to yield=0pps -> DEGRADED -> motion=0 (#521, #954). Fix (additive): pin a ~50 Hz OFDM unicast floor by pinging the STA's own DHCP gateway. The router's ICMP echo replies are OFDM frames destined to this station and drive the CSI engine regardless of promiscuous filter state or ambient traffic. Mirrors Espressif's esp-csi csi_recv_router reference. Promiscuous capture (#396/#893) is left fully intact so multistatic/multi-node sensing still hears other stations' frames. Reconciles PR #955 (which removed promiscuous entirely and conflicted with the already-shipped #893 DATA-capture path) into an additive change on current main. Verified on ESP32-S3 (N16R8, COM8), ESP-IDF v5.4: Promiscuous mode enabled (MGMT-only, RuView#396) self-ping started -> 192.168.1.1 @50Hz (CSI OFDM source, fix #521/#954) CSI cb #1: len=128 rssi=-40 ch=5 adaptive_ctrl: state=6 yield=13-19pps motion=1.00 presence>0 (SENSE_ACTIVE) DEGRADED cleared; CSI yield stable ~15 pps over 60 s. Co-authored-by: Meraj <merajmehrabi@gmail.com>
|
Thanks for the root-cause and the fix, @merajmehrabi — your self-ping diagnosis was correct and verified on our ESP32-S3 (COM8). We landed it as #985 (merged to #985 keeps #396/#893 intact and adds your gateway self-ping as a guaranteed ~50 Hz OFDM floor — which also fixes the display-build edge case from the #954 thread. You're credited as co-author on the squashed commit. Closing this as superseded by #985. 🙏 |
Problem
On ESP32-S3,
wifi_csi_callbacknever fires —pkt_yield=0pps, the ADR-081 adaptive controller stays inADAPT_STATE_DEGRADED, and everyrv_feature_state_tpacket readsmotion=0, presence=0, DEGRADED. The node streams but senses nothing. Reproduced on v0.6.5 and v0.7.0, on 3 boards, on both HT40 and HT20 APs. (Same symptom as #954 and the closed #521.)Root cause
The ESP32 CSI engine only produces CSI for received OFDM frames (it measures the L-LTF/HT-LTF training fields).
csi_collector_init()captured CSI only through a MGMT-only promiscuous filter (the #396 Core-0 DATA-sniff crash workaround), so the only CSI-eligible frames were beacons — which APs almost always transmit at non-OFDM DSSS basic rates (1–2 Mbps) that carry no training field. Net: zero CSI-eligible frames → zero callbacks.The OFDM traffic source the comments describe ("probe request injection at 10 Hz") does not exist —
csi_inject_ndp_frame()has no callers and is a TX-only null-data stub anyway (TX does not generate CSI).The prior #521 fix —
esp_wifi_set_ps(WIFI_PS_NONE)— was a wrong diagnosis (modem sleep) committed without a hardware check; it is present in current firmware and the symptom persists.Fix
Mirror Espressif's reference (
esp-csi/examples/get-started/csi_recv_router): use plain connected-STA CSI and generate received OFDM frames by pinging the gateway at 50 Hz (esp_ping). Each ICMP echo reply is a unicast OFDM data frame addressed to the station → the CSI engine fires.Disabling promiscuous mode also removes the #396 Core-0 crash surface entirely (we no longer sniff DATA frames; we only receive our own low-rate replies).
Verification (ESP32-S3 N16R8, ESP-IDF v5.4)
Host-side decode of
0xC5110006:DEGRADED 0/70,PRES_VALID|RESP_VALID|HB_VALID, breathing ≈ 9–13 bpm and heart rate ≈ 40–46 bpm computed.Notes / follow-ups
motionsaturates at 1.00 in early testing — likely the constant self-ping baseline; the motion threshold/normalisation may want a follow-up tune.firmware/esp32-csi-node/main/csi_collector.c); builds clean foresp32s3, 47% app partition free.Closes #954. Supersedes the unverified #521 fix.