Conversation
…fields that were always zero `node_log_periodic_t` has declared `frames_processed` and `frames_rejected` since the on-node log shipped, and `node_log_read.py` has always rendered both. Nothing ever assigned them. `fill_health()` memsets the struct and fills 20 of its 25 fields; these two are not among them, so every periodic record on every node reports 0/0 -- the memset, not a measurement. That is the most misleading pair of values this record can carry. `EDGE_MAX_SUBCARRIERS` is target-conditional: `edge_processing.h` picks 256 on `CONFIG_SOC_WIFI_HE_SUPPORT` and 128 otherwise, and `process_frame()` opens with `n_subcarriers > EDGE_MAX_SUBCARRIERS -> return`. A C6 that resolves the guard to 128 therefore rejects every HE20 frame while the Edge DSP task still starts and logs its banner. From outside, an edge stage that is idle and one that is rejecting 100% of frames look identical -- and the log whose entire purpose is diagnosing a node you cannot reach answered that question with a plausible constant zero. Half the data was already here: `s_frame_count` exists and is incremented on the accept path. Only the reject path was uncounted, so this adds `s_frame_rejected` next to it, increments it in the guard instead of returning silently, resets it alongside `s_frame_count` in init, exposes both through accessors, and wires them into `fill_health()`. Measured, not argued. Found by reading a real node's log: `frames_processed=0` across 64 records at 5.5 days uptime with CSI flowing at 19 fps, which reads as a dead edge pipeline and was very nearly reported as one. After this change, rolled across nine ESP32-C6 nodes: ``` node fps processed rejected heap rssi 0 18.0 2007 0 188K -67 1 23.0 1527 0 187K -70 2 32.0 1538 0 188K -51 3 27.0 3447 0 187K -66 4 26.0 1045 0 187K -60 5 23.0 565 0 188K -72 6 29.0 571 0 188K -72 7 27.0 87 0 184K -75 8 30.0 90 0 188K -67 ``` Non-zero processed with zero rejected on all nine is also the first runtime evidence that the guard is sized correctly on C6. At 128 the inequality inverts: every frame rejected, none processed. That was previously arguable only from include order. Builds clean for esp32c6 on this base; both accessors are present in the linked ELF. The only `main/` diagnostic is the pre-existing unused-variable warning in `mmwave_sensor.c:246`. Co-Authored-By: claude-flow <ruv@ruv.net>
|
Ty |
oga35767-eng
approved these changes
Sep 15, 2026
|
Yy |
… KiB Unblocks the "Verify binary size budget" step of Build firmware (esp32s3 / 8mb) -- this branch's head already carries the image growth from 130afab but was still checked against the old 1152 KiB limit. Does not address this branch's separate RUSTSEC-2026-0285 (rustls) failure on Rust Dependency Audit. Co-Authored-By: claude-flow <ruv@ruv.net>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
node_log_periodic_thas declaredframes_processedandframes_rejectedsince the on-node log shipped, and
node_log_read.pyhas always renderedboth. Nothing ever assigned them.
fill_health()memsets the struct and fills20 of its 25 fields; these two are not among them, so every periodic record
on every node reports 0/0 — the memset, not a measurement.
Why these two specifically matter
EDGE_MAX_SUBCARRIERSis target-conditional —edge_processing.hpicks 256on
CONFIG_SOC_WIFI_HE_SUPPORTand 128 otherwise — andprocess_frame()opens with
n_subcarriers > EDGE_MAX_SUBCARRIERS -> return. A C6 thatresolves that guard to 128 rejects every HE20 frame while the Edge DSP
task still starts and logs its banner.
From outside, "the edge stage is idle" and "the edge stage is rejecting 100%
of frames" look identical. The log exists to diagnose a node you cannot
reach, and on exactly that question it was returning a plausible constant
zero.
The change
Half the data was already here —
s_frame_countexists and is incremented onthe accept path. Only the reject path was uncounted. So:
s_frame_rejectedbesides_frame_counts_frame_countinedge_processing_init()edge_processing_get_frames_processed/rejected()fill_health()Three files, ~15 lines net.
Measured
Found by reading a real node's log:
frames_processed=0across 64 records at5.5 days uptime with CSI flowing at 19 fps. That reads as a dead edge
pipeline and was very nearly reported as one — it was the logging.
After the change, rolled across nine ESP32-C6 nodes:
Non-zero processed with zero rejected on all nine is also the first runtime
evidence that the guard is sized correctly on C6 — at 128 the inequality
inverts. That was previously arguable only from include order.
Verification
Builds clean for
esp32c6on this base, and both accessors are present inthe linked ELF (
riscv32-esp-elf-nm). The onlymain/diagnostic is thepre-existing unused-variable warning at
mmwave_sensor.c:246.Not included
Five more fields in the same record are unpopulated for the same reason —
seq_drop,tx_early_drop,tx_rate_skip,leader_id,mesh_staleness_ms,mesh_seq. Each needs a new accessor rather than anexisting one, so they are a separate change. The underlying issue is that the
struct,
fill_health()andnode_log_read.pyare three places that mustagree and nothing checks that they do — a test asserting every field is
written would stop the next one landing the same way. Happy to add that here
if you would prefer it in one go.
🤖 Generated with claude-flow