Skip to content

RS-11.5 legs D–F: TX digital path proven clean in-firmware; corruption follows the receiver; overload refuted - #94

Merged
dorkmo merged 9 commits into
mainfrom
rs115-fw-discriminators
Aug 2, 2026
Merged

RS-11.5 legs D–F: TX digital path proven clean in-firmware; corruption follows the receiver; overload refuted#94
dorkmo merged 9 commits into
mainfrom
rs115-fw-discriminators

Conversation

@dorkmo

@dorkmo dorkmo commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Continues the RS-11.5 investigation from PR #93 with experimental firmware and three on-air discriminating legs. Full record in bench-evidence/RS_11_4_train_length_sweep_2026-08-02/RESULTS.md §9–§14.

New firmware instrumentation (flashed to the tractor, SWD/AN3155, RC=0)

  • Post-TX FIFO readback: DJB checksum at load, chunked re-read + compare after TX_DONE (SX1276 retains the FIFO in STANDBY). Mismatch ⇒ radiated bits were corrupt at the source.
  • Early-TX_DONE check: TX_DONE >5 ms before expected ToA ⇒ truncated radiation (poll latency can only lengthen the measurement — no false positives).
  • Reported via three additive STATS counters (payload 132→144, host label lists offset-guarded) + FAULT URCs 0x0D/0x0E carrying the fragment's tx_id. All 27 bench check targets pass; size budget passes.
  • Two host-side diagnostic knobs added along the way: LIFETRAC_TX_POWER_DBM (CFG_SET at startup; can only lower below the ERP-clamped ceiling) and the leg-C LIFETRAC_RXCONT_ARM from PR RS-11.5 leg C: RXCONT turnaround exonerated — software discriminator space closed #93.

The three legs

leg setup result
D instrumented forward run 2468/2468 FIFO readbacks intact, zero early TX_DONEs — base still took +110 CRC. TX digital path exonerated by direct measurement.
E′ manual role swap (base TX ← PC-broker host feed; tractor RX) Corruption follows the receiver: tractor-as-RX 6.6%, uniform across the train; base-as-RX 3–4.5%, slot-(total−2) locked. Both boards clean as TX.
F forward roles at 2 dBm (vs 14) CRC rate unchanged (3.9%) — front-end overload refuted.

Plus the §8 idle-floor argument: ~4 false-demod CRC events/hour when idle vs 75–170 per 300 s active — ambient interference refuted three orders of magnitude over.

Where the diagnosis now stands

~4% of our own fragments arrive payload-corrupt at the receiver (header demodulates, payload CRC fails), in both directions, at both power levels, with the transmit chain proven intact. Everything software, everything digital-TX, overload, ambient RF, and unit-specific hardware are eliminated by measurement. Remaining hypothesis space: receiver-side host/board coupling into demodulation (the base's train-position lock hints at something periodic on the receiving host) or board-level EMI with per-board signatures.

Recommended next steps (in the TODO): a physical separation/orientation change at the bench (requires hands — no RF gear available), or an RX-side firmware capture increment (IRQ flags + RSSI + corrupt-payload dump) as the next flash session.

Bench state: daemons stopped, radios idle; the tractor L072 runs the instrumented build (production-equivalent + additive diagnostics); TX power reverts to the profile default at next daemon startup without the env.

Suite: 1103/2446 green. The known-red check_mh_wire_sync remains red as on main (pre-existing H7/L072 schema drift; the additive STATS growth is noted there).

🤖 Generated with Claude Code

dorkmo and others added 4 commits August 2, 2026 09:43
…are space closed

New diagnostic gate LIFETRAC_RXCONT_ARM (daemon env + harness
-RxcontArm, production default 1): 0 disables all RXCONT arming so the
firmware's RS-4.12 re-arm chain never starts and the radio sits in
STANDBY between fragments. NEVER ship 0 — in-stream command delivery
(99.8%) lives in those listening gaps and inter-train-only delivery
would blow the 700 ms control latency budget.

Leg C result (300 s @ 3000 B, probe-bracketed, archive committed): the
slot-(total-2) spike is UNCHANGED with no turnaround cycling (idx11
22/66 attributed, CRC delta +62 vs +75/+80 in legs A/B). With this,
every software-layer candidate is eliminated; the corruption is
physical/silicon in the TX chain or deterministic self-EMI. Next
discriminators need a flash session (post-TX FIFO readback CRC,
measured TX duration in RFCO, IRQ-flag capture) or an SDR capture.

Also recorded: idle-bench ambient false-demod CRC floor ~4/h (negligible
vs 62-80 per 300 s run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…TX_DONE

Instruments the L072 TX path to discriminate the slot-(total-2) on-air
CRC corruption (all software layers exonerated by legs A-C):

- Load-time DJB checksum over the FIFO content (hop header + payload);
  after TX_DONE the FIFO is re-read in 32-byte chunks (SX1276 retains it
  in STANDBY) and compared. Mismatch = the radiated bits were corrupt at
  the source.
- TX_DONE arriving >5 ms before the expected ToA = truncated radiation
  (poll latency only ever lengthens the measurement — no false
  positives).

Reporting: three additive STATS counters (payload 132->144; host
parse_stats label lists are offset-guarded and updated) plus FAULT URCs
0x0D/0x0E whose sub byte carries the fragment tx_id (== index), so the
tx daemon log shows WHICH slot misbehaved. The readback costs ~1-2 ms
inside the ~17 ms inter-fragment gap; if the corruption vanishes under
instrumentation, that timing sensitivity is itself a finding.

Bench stubs extended for check-tx-len-guard. All 27 check targets PASS;
size budget PASS (23,388 B / 184 KB). Note: check_mh_wire_sync remains
red as on main (pre-existing H7/L072 schema drift, 68 vs now 144).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… on air

Leg D (instrumented firmware, flashed): 2468/2468 FIFO readbacks intact,
zero early TX_DONEs, zero FAULTs — while the base still took +110 CRC
errors. The transmitter's digital path (host feed -> mailbox -> FIFO ->
duration) is exonerated by direct measurement; corruption enters between
modulator and demodulator.

Leg E (role swap) aborted with no data: the harness TX image exists only
on the tractor and lifetrac-v25 lacks numpy for the synth publisher.
Learned in passing: the SWD reset path works on the base board (its L072
counters now zeroed — substitute for the dead gpio163), and the proper
swap recipe is -TxFeed host with the tx daemon in lifetrac-v25.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…; overload refuted

Leg E' (manual role swap, base TX via PC-broker host feed): both boards
corrupt as receivers, both clean as transmitters — unit hardware defect
eliminated. Shape is board-specific: tractor-as-RX 6.6% UNIFORM across
the train; base-as-RX 3-4.5% locked at slot total-2.

Leg F (new LIFETRAC_TX_POWER_DBM host knob, CFG_SET at startup, can only
lower below the ERP ceiling): 2 dBm vs 14 dBm leaves the CRC rate
unchanged (3.9%) — front-end overload refuted. The overnight idle floor
(~4 CRC/h vs 75-170 per 300 s active) refutes ambient interference.

Final diagnosis state: ~4% of our own fragments arrive payload-corrupt
at the receiver, both directions, power-independent, TX digital path
proven intact in-firmware. Remaining: receiver-side host/board coupling
or board EMI. Next: physical separation test (needs hands) or RX-side
firmware capture increment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 2, 2026 16:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the RS-11.5 on-air corruption investigation by adding firmware-level TX-path discriminators (FIFO post-TX readback + early-TX_DONE detection), extending host-visible stats/fault reporting, and adding host-side harness knobs to run discriminating bench legs (RXCONT disable and TX power override). The accompanying bench-evidence updates document legs C and D–F and the resulting narrowed hypothesis space (corruption follows the receiver; TX digital path and overload refuted).

Changes:

  • Add Murata L072 firmware instrumentation to detect TX FIFO mutation and truncated transmissions, reporting via new STATS counters and FAULT URCs.
  • Extend host STATS payload/parsing to include the new discriminator counters.
  • Add host/harness controls for RS-11.5 diagnostics (LIFETRAC_RXCONT_ARM, LIFETRAC_TX_POWER_DBM) and update bench evidence/TODO narrative.

Reviewed changes

Copilot reviewed 14 out of 26 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
LifeTrac-v25/DESIGN-CONTROLLER/TODO.md Updates the running RS-11.5 investigation notes with legs C and D–F conclusions and next steps.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/x8_lora_bootloader_helper/run_live_radio_monitor.ps1 Adds -RxcontArm harness parameter and plumbs it into the TX daemon container env.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/x8_lora_bootloader_helper/rs115_stats_probe.py Updates stats probe to print the newly added discriminator counters.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/x8_lora_bootloader_helper/method_g_stage1_probe.py Extends STATS label list to parse the new additive counters with length guards.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/tractor_x8/image_tx_daemon.py Adds LIFETRAC_RXCONT_ARM gate and LIFETRAC_TX_POWER_DBM CFG_SET diagnostic override.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/murata_l072/radio/sx1276_tx.c Implements TX discriminators: FIFO checksum at load, post-TX FIFO readback compare, and early-TX_DONE timing check with fault emission.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/murata_l072/include/host_types.h Extends STATS wire payload length/offsets and adds new fault codes 0x0D/0x0E.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/murata_l072/include/host_stats.h Declares new host_stats increment functions for the discriminator counters.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/murata_l072/host/host_stats.c Adds storage/serialization for the new discriminator counters at the STATS tail.
LifeTrac-v25/DESIGN-CONTROLLER/firmware/murata_l072/bench/host_proto/tx_len_guard.c Adds stubs needed for the new TX discriminator hooks in host-compiled bench tests.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/RS_11_4_train_length_sweep_2026-08-02/RESULTS.md Documents leg C and legs D–F results and the updated diagnosis.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/RS_11_4_train_length_sweep_2026-08-02/leg_f_rx_extract.log Evidence artifact referenced by RESULTS updates.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/RS_11_4_train_length_sweep_2026-08-02/leg_f_power_drop.log Evidence log for the TX power drop discriminator run (leg F).
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/RS_11_4_train_length_sweep_2026-08-02/leg_e_swap_rx_extract.log Evidence log for the manual role-swap discriminator run (leg E′).
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_110209_87821c90/tx_daemon.log Archived harness output for an aborted run attempt.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_110209_87821c90/synth_pub.log Archived harness output for an aborted run attempt.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_110209_87821c90/rx_daemon.log Archived harness output for an aborted run attempt.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_110209_87821c90/params.txt Archived parameter capture for an aborted run attempt.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_105435_87821c90/tx_daemon.log Archived TX daemon log for the instrumented-firmware run (leg D context).
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_105435_87821c90/synth_pub.log Archived synthetic publisher log for the instrumented-firmware run.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_105435_87821c90/rx_daemon.log Archived RX daemon log for the instrumented-firmware run.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_105435_87821c90/params.txt Archived parameter capture for the instrumented-firmware run.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_094053_86bf5d7f/tx_daemon.log Archived TX daemon log for the RXCONT-disabled run (leg C context).
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_094053_86bf5d7f/synth_pub.log Archived synthetic publisher log for the RXCONT-disabled run.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_094053_86bf5d7f/rx_daemon.log Archived RX daemon log for the RXCONT-disabled run.
LifeTrac-v25/DESIGN-CONTROLLER/bench-evidence/radio_monitor_20260802_094053_86bf5d7f/params.txt Archived parameter capture for the RXCONT-disabled run.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +133 to +134
# corruption mechanism). Production default 1.
[int]$RxcontArm = 1,
Comment on lines +608 to +622
# RS-11.5 diagnostic (2026-08-02): optional TX power override for the
# front-end-overload discriminator (bench antennas sit inches apart
# at the default 14 dBm). Empty = leave the firmware default alone.
# Regulatory: the firmware's ERP clamp still applies — this can only
# LOWER power below the configured ceiling on the bench.
tx_dbm = _os.environ.get("LIFETRAC_TX_POWER_DBM", "").strip()
if tx_dbm:
try:
dbm = int(tx_dbm)
link.request(HOST_TYPE_CFG_SET_REQ, HOST_TYPE_CFG_OK_URC,
bytes([CFG_KEY_TX_POWER_DBM, 0x01, dbm & 0xFF]),
timeout=1.0)
LOG.warning("RS-11.5 diagnostic: TX_POWER_DBM=%d", dbm)
except Exception as exc: # pragma: no cover
LOG.warning("CFG_SET(TX_POWER_DBM=%s) failed: %s", tx_dbm, exc)
dorkmo and others added 5 commits August 2, 2026 13:32
New RX_CRC_DUMP_URC (0xC5): on every payload-CRC failure the L072 ships
IRQ flags, packet RSSI/SNR, length, and the corrupt bytes (reuses the
caller's frame buffer; ~0.3/s at the observed rate). Both boards
flashed; rx daemon logs each dump; 126 captured in one 300 s run.

The dumps answer everything: our fragments arrive at -97 dBm mean /
~0-6 dB SNR — the bench deliberately runs ANTENNA-LESS (HIL_RUNBOOK:
"no antennas attached") on leakage coupling, and the ~4% loss is
ordinary noise-floor single-bit corruption ("WEBP"->"WMBP"-class
flips), uniform across positions, no truncation or fill patterns.

Reassessed per the corrections discipline: the penultimate "position
lock" was an attribution-observability artifact (dump-level truth is
uniform — trust the instrument as a counter, not its per-index shape);
leg F softens to "the corrupt fraction is set by the floor-adjacent
regime" (the 2 dBm CFG did reach the PA; overload still refuted).

RS-11.5 closed: fix = the pending antenna installation; RS-11.6 queued
for the post-antenna re-baseline. Also adds LIFETRAC_TX_POWER_DBM
(diagnostic, ERP-clamped) from leg F. Suite 1103/2446; 27 fw checks +
size budget PASS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ough the TX-RFO arm

Operator input corrected the RS-11.5 closure: the bench has antennas
(Wurth Hermippe-III 868 MHz 2.5 dBi SMA on both Max Carriers) — the
"antenna-less by design" reading mis-generalized a HIL_RUNBOOK line
about the H7 rig. With antennas present, -97 dBm at bench range was
~60 dB of missing budget, and the firmware audit found it: the ABZ
switch truth table is PA1=CRF1 (RX), PC1=CRF2 (TX-RFO), PC2=CRF3
(PA_BOOST), exactly one high per mode — but both switch drivers
treated PA1 as a TX/RX direction pin and drove the TX-RFO arm high in
RX. Fixed in sx1276.c and sx1276_modes.c.

Leg H verification (both boards reflashed, archive committed):
corrupt-dump RSSI mean -96.8 -> -64.3 dBm (+33 dB recovered). SNR
stayed at ~+1.7 mean — the noise floor rose WITH the signal, i.e. the
remaining limiter is broadband interference entering the same antenna
path (bench-local EMI; USB3/DDR at ~900 MHz is the prime suspect, and
it also explains leg F's null on the broken switch: signal and
interference were attenuated together). Legs I/J (2 vs 17 dBm on the
fixed switch) run the SIR discriminator; harness gains -TxPowerDbm.

Also records the 868-vs-915 MHz antenna detuning (few dB, secondary;
US-band swap worth queuing).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lf-interference

Power sweep on the fixed switch (new -TxPowerDbm): 2 dBm -> 6.3% loss,
14 -> 5.4%, 17 -> 4.0% — mildly power-responsive, and the corrupt
population sits at ~+2 dB SNR at every power and both switch configs
(noise tracks our own signal across ~48 dB of combined change). A
fixed external interferer cannot do that: the residual floor is
signal-proportional self-interference at bench geometry (close-range
multipath / near-field coupling, detuned 868 MHz antennas).

Final closure: (1) the ABZ switch-mapping bug is fixed, +33 dB
verified — ships regardless of bench; (2) the residual ~4% floor at
17 dBm awaits the antenna-position experiment (RS-11.6, user's
hands-on task) on a rig that now reads corrupt packets directly;
(3) bench runs get a free ~1.4x loss cut at -TxPowerDbm 17. Caveat
recorded: healthy-frame SNR logging is the missing instrument.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…H31)

Operator decision 2026-08-02: field antennas will be Taoglas TD.95.6H31
Blade (868/915 MHz dual-band omnidirectional dipole, terminal mount) —
properly tuned for the 902-928 MHz operating band, unlike the bench's
868-only Hermippe-III units. ~2 dBi-class gain sits under the FCC
§15.247 6 dBi threshold, so no ERP power reduction; the datasheet gain
goes into the field profile's antenna_gain CFG at provisioning.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dation, power clamp

Copilot findings, all valid:
- Archived params.txt now records rxcont_arm and tx_power_dbm (the two
  new run-affecting knobs were invisible in evidence bundles — the
  PR #93 catch, applied here on the stacked branch).
- -RxcontArm gets [ValidateSet(0,1)] — any non-1 int silently disabled
  RXCONT (the daemon checks == "1").
- LIFETRAC_TX_POWER_DBM is range-checked host-side to 2..17 before the
  wire: a negative value wrapped via & 0xFF to 255, which the firmware
  normalizes DOWN to 17 dBm — junk input could silently RAISE power.
  Out-of-range now warns and leaves the profile default.

Suite 1103/2446 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dorkmo
dorkmo merged commit 9d0d32c into main Aug 2, 2026
10 of 22 checks passed
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.

2 participants