Merge pull request #906 from ruvnet/fix/893-csi-data-frame-capture

fix(firmware): capture DATA frames on display-less boards — #893/#866/#897 (yield=0pps root cause)
This commit is contained in:
rUv 2026-06-02 04:23:44 -04:00 committed by GitHub
commit 3fec67654a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 64 additions and 0 deletions

View File

@ -637,6 +637,23 @@ static void hop_timer_cb(void *arg)
csi_hop_next_channel(); csi_hop_next_channel();
} }
void csi_collector_enable_data_capture(void)
{
/* MGMT-only (RuView#396) starves the CSI callback on display-less boards
* (RuView#521/#893): beacons alone are sparse, yield collapses to 0 pps.
* Without a display there is no QSPI/SPI-flash cache contention with the
* DATA-frame interrupt load, so capture DATA frames too. */
wifi_promiscuous_filter_t filt = {
.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT | WIFI_PROMIS_FILTER_MASK_DATA,
};
esp_err_t err = esp_wifi_set_promiscuous_filter(&filt);
if (err == ESP_OK) {
ESP_LOGI(TAG, "CSI filter upgraded to MGMT+DATA (no display, RuView#893)");
} else {
ESP_LOGW(TAG, "Failed to enable DATA-frame CSI capture: %s", esp_err_to_name(err));
}
}
void csi_collector_start_hop_timer(void) void csi_collector_start_hop_timer(void)
{ {
if (s_hop_count <= 1) { if (s_hop_count <= 1) {

View File

@ -90,6 +90,19 @@ void csi_hop_next_channel(void);
*/ */
void csi_collector_start_hop_timer(void); void csi_collector_start_hop_timer(void);
/**
* Upgrade the promiscuous filter to capture DATA frames in addition to MGMT
* (RuView#893/#521).
*
* Called on display-less boards: the MGMT-only filter (the #396 display-crash
* workaround set in csi_collector_init) only fires the CSI callback on sparse
* management frames, so yield collapses to 0 pps under real traffic and the
* node looks dead. A board with no AMOLED panel has no QSPI/SPI-flash cache
* contention, so it can safely capture DATA frames restoring abundant CSI.
* Display boards keep MGMT-only to avoid the #396 crash.
*/
void csi_collector_enable_data_capture(void);
/** /**
* Inject an NDP (Null Data Packet) frame for sensing. * Inject an NDP (Null Data Packet) frame for sensing.
* *

View File

@ -9,6 +9,14 @@
#include "display_task.h" #include "display_task.h"
#include "sdkconfig.h" #include "sdkconfig.h"
/* Set true once an AMOLED panel is detected and the display task starts.
* Defined outside the CONFIG_DISPLAY_ENABLE guard so display_is_active()
* exists on headless builds too (where it stays false CSI captures DATA
* frames; see RuView#893). */
static bool s_display_active = false;
bool display_is_active(void) { return s_display_active; }
#if CONFIG_DISPLAY_ENABLE #if CONFIG_DISPLAY_ENABLE
#include <string.h> #include <string.h>
@ -162,6 +170,7 @@ esp_err_t display_task_start(void)
ESP_LOGI(TAG, "Display task started (Core %d, priority %d, %d fps)", ESP_LOGI(TAG, "Display task started (Core %d, priority %d, %d fps)",
DISP_TASK_CORE, DISP_TASK_PRIORITY, DISP_FPS_LIMIT); DISP_TASK_CORE, DISP_TASK_PRIORITY, DISP_FPS_LIMIT);
s_display_active = true;
return ESP_OK; return ESP_OK;
} }

View File

@ -7,6 +7,7 @@
#define DISPLAY_TASK_H #define DISPLAY_TASK_H
#include "esp_err.h" #include "esp_err.h"
#include <stdbool.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -22,6 +23,15 @@ extern "C" {
*/ */
esp_err_t display_task_start(void); esp_err_t display_task_start(void);
/**
* @return true once an AMOLED panel has been detected and the display task
* is running; false on headless boards (no panel, or built without display
* support). Used to choose the CSI promiscuous filter (RuView#893): a board
* with no display has no QSPI/SPI-flash contention, so it can safely capture
* DATA frames for proper CSI yield instead of starving on MGMT-only.
*/
bool display_is_active(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -410,6 +410,21 @@ void app_main(void)
} }
#endif #endif
/* RuView#893/#521: the MGMT-only promiscuous filter (set in
* csi_collector_init as the #396 display-crash workaround) starves the CSI
* callback on display-less boards yield collapses to 0 pps and the node
* looks dead despite being on the network. Now that the display probe has
* run, boards with no AMOLED panel (no QSPI/SPI-flash cache contention)
* upgrade the filter to capture DATA frames too, restoring CSI yield. */
#ifdef CONFIG_DISPLAY_ENABLE
bool has_display = display_is_active(); /* runtime panel probe result */
#else
bool has_display = false; /* display support not compiled in */
#endif
if (!has_display) {
csi_collector_enable_data_capture();
}
ESP_LOGI(TAG, "CSI streaming active → %s:%d (edge_tier=%u, OTA=%s, WASM=%s, mmWave=%s, swarm=%s, adapt=%s)", ESP_LOGI(TAG, "CSI streaming active → %s:%d (edge_tier=%u, OTA=%s, WASM=%s, mmWave=%s, swarm=%s, adapt=%s)",
g_nvs_config.target_ip, g_nvs_config.target_port, g_nvs_config.target_ip, g_nvs_config.target_port,
g_nvs_config.edge_tier, g_nvs_config.edge_tier,