Skip to content

fix(firmware): derive feature_state emit divider from fast-loop period - #1498

Open
fallen-pc wants to merge 1 commit into
ruvnet:mainfrom
fallen-pc:fix/feature-state-emit-divider
Open

fix(firmware): derive feature_state emit divider from fast-loop period#1498
fallen-pc wants to merge 1 commit into
ruvnet:mainfrom
fallen-pc:fix/feature-state-emit-divider

Conversation

@fallen-pc

Copy link
Copy Markdown

Problem

fast_loop_cb() emits feature_state every 5th tick:

static uint8_t s_emit_divider = 0;
if (++s_emit_divider >= 5) {

That produces the intended 1 Hz only at the 200 ms ADAPTIVE_FAST_LOOP_MS default. Kconfig permits 50-2000 ms (main/Kconfig.projbuild), so a node tuned toward the 50 ms floor emits at 4 Hz - reintroducing the exact WiFi TX-airtime saturation the divider was added to prevent, documented in the comment directly above it (sendto ENOMEM - backing off 100 ms, ~90% of CSI frames dropped before reaching the host).

Fix

Derive the divider from the configured period instead:

uint16_t emit_every = FEATURE_STATE_PERIOD_MS / s_cfg.fast_loop_ms;
if (emit_every == 0) emit_every = 1;
  • No behaviour change at the default - 1000 / 200 still evaluates to 5.
  • At the 50 ms floor: 1000 / 50 = 20, so 1 Hz instead of 4 Hz.
  • The == 0 guard covers fast_loop_ms > 1000.
  • Divide-by-zero is not reachable: adaptive_controller_start() clamps fast_loop_ms to >= 50 before the timers are created.

Also refreshed the note in sdkconfig.defaults, which still described this rate-limit as "a code refactor tracked in a separate follow-up issue" - it has since landed in fast_loop_cb().

Testing

  • idf.py build (ESP-IDF v5.4 Docker, esp32s3) - clean; binary 910 KB, under the 950 KB CI gate.
  • Not yet exercised on hardware at a non-default ADAPTIVE_FAST_LOOP_MS; the default path is unchanged and running on 6x ESP32-S3-DevKitC-1 here.

fast_loop_cb() emitted feature_state every 5th tick, which yields the
intended 1 Hz only at the 200 ms ADAPTIVE_FAST_LOOP_MS default. Kconfig
permits 50-2000 ms, so a node tuned toward the 50 ms floor emitted at 4 Hz
and reintroduced the WiFi TX-airtime saturation the divider was added to
prevent (sendto ENOMEM backoff, ~90% of CSI frames dropped before reaching
the host).

Compute the divider as FEATURE_STATE_PERIOD_MS / fast_loop_ms with a floor
of 1. Behaviour at the 200 ms default is unchanged - the expression still
evaluates to 5.

Also refresh the note in sdkconfig.defaults that still described this
rate-limit as an unimplemented follow-up; it landed in fast_loop_cb().

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant