Skip to content

Dwell-1 A/B injection: a two-context per-slot data plane (exp 4/5)#321

Merged
josephnef merged 1 commit into
masterfrom
dwell1-ab-injection
Jul 20, 2026
Merged

Dwell-1 A/B injection: a two-context per-slot data plane (exp 4/5)#321
josephnef merged 1 commit into
masterfrom
dwell1-ab-injection

Conversation

@josephnef

Copy link
Copy Markdown
Collaborator

Closes #272.

Fourth in the standard-driver FHSS series. #272 was premised on the MCC/FCS scheduler from #271, which #271 rejected — so this reframes onto the vehicle the series already validated (the ordinary channel switch) and answers #272's actual question: can firmware-grade channel time-slicing carry a real per-slot data plane with deterministic queue ownership? It can.

What it is

A new examples/dwelltx demo runs a two-context A/B schedule — one wall-clock slot per channel — and admits exactly one data-frame opportunity per slot ("dwell-1") inside a bounded window that guarantees the frame finishes airing before the slot flips. Past the deadline the frame is dropped with a structured reason, so a frame built for context A can never air on B. This bounded admission is pure caller policy; the library is unchanged.

Each per-slot frame carries a HopSyncMarker (src/HopSchedule.h) whose slot maps, through the shared schedule, to the channel that slot belongs to — so a fixed-channel oracle that decodes an out-of-context frame is a self-evident wrong-channel event, and attribution needs no cross-clock alignment. tests/dwell1_ab.py drives two oracles (A/B) with per-slot accounting, fault injection, and the switch-primitive comparison.

On-air results (RTL8822BU DUT, 8821AU + 8812CU oracles)

run slots delivered correct channel wrong-channel dup late-drop
primary 5 020 97.2 % 0 0 0
reliability 100 013 96.2 % 0 0 7 (0.007 %)
  • Zero wrong-channel and zero duplicates over 100 k slots; admit jitter p99−p1 = 132 µs. The ~4 % shortfall is first-decode/settle loss, not mis-delivery.
  • Fault (late enqueue, 18 ms into a 20 ms slot): 511/516 dropped-late, zero mis-aired — overload is deterministic.
  • Lockstep RX: a single receiver acquires the schedule from the markers (889 tracked decodes/12 s) and re-acquires from a cold restart (861), no persistent phase inversion.

Key finding — the two switch primitives have opposite sweet spots

Running the identical loop over the firmware switch (DEVOURER_FASTRETUNE_FW) inverts the dwell-1 schedule at 20 ms slots: in the sparse one-retune-per-slot pattern its fire-and-confirm-later RF completes far later than the ~1 ms it shows under continuous hopping (settle sweep: 3 % → 82 % delivery as settle goes 2 → 12 ms). The synchronous FastRetune — RF programmed by the time the call returns — places the frame deterministically with a ~2 ms settle and is the correct dwell-1 primitive. This composes with experiments 2–3 rather than contradicting them: firmware switch for throughput hopping, synchronous switch for deterministic slot placement.

Go/no-go: go — advance to experiment 5, using the synchronous switch for the slot data plane. Full note: docs/dwell1-ab-injection.md.

🤖 Generated with Claude Code

The data-plane experiment #271 could not run on MCC (rejected) reframed onto
the ordinary channel switch: examples/dwelltx spends one wall-clock slot per
channel on an A/B schedule and admits exactly one data frame per slot inside a
bounded window, so a frame built for context A can never air on B. Each frame
carries a HopSyncMarker whose slot maps to the expected channel, so a
fixed-channel oracle that decodes an out-of-context frame is a self-evident
wrong-channel event — attribution needs no cross-clock alignment. Pure caller
policy; the library is unchanged.

On-air (RTL8822BU DUT, two oracles; tests/dwell1_ab.py): over 100,013 A/B
slots at 20 ms, zero wrong-channel, zero duplicate re-airs, 96.2 % delivered
on the correct channel, 7 late-drops (0.007 %); admit jitter p99-p1 132 us.
Late enqueue past the slot deadline drops deterministically (511/516),
never mis-airs. A single receiver acquires the schedule from the markers
alone and re-acquires from a cold restart (889 / 861 lockstep decodes).

Key finding — the two switch primitives have opposite sweet spots. The
synchronous FastRetune carries dwell-1 cleanly; the fire-and-confirm-later
firmware switch (DEVOURER_FASTRETUNE_FW, which halves continuous-hop dark time
in exp 2-3) needs >12 ms of settle inside a 20 ms slot because its RF
completes late in the sparse dwell-1 call pattern — firmware switch for
throughput hopping, synchronous switch for deterministic slot placement.
Go: advance to exp 5. Full note: docs/dwell1-ab-injection.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@josephnef
josephnef force-pushed the dwell1-ab-injection branch from f8c6de1 to 53fde02 Compare July 20, 2026 13:19
@josephnef
josephnef merged commit 0d52fa5 into master Jul 20, 2026
18 checks passed
@josephnef
josephnef deleted the dwell1-ab-injection branch July 20, 2026 13:28
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.

Standard-driver FHSS experiment 4/5: A/B dwell-1 injection over MCC/FCS

1 participant