Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions .github/workflows/l072-bench-md5.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ env:
# checked 2026-10-10 against Arm's published .sha256asc (170 644 784 B).
ARM_TOOLCHAIN_URL: https://developer.arm.com/-/media/Files/downloads/gnu/12.2.mpacbti-rel1/binrel/arm-gnu-toolchain-12.2.mpacbti-rel1-x86_64-arm-none-eabi.tar.xz
ARM_TOOLCHAIN_SHA256: 17455a06c816031cc2c66243c117cba48463cd6a3a3fdfac7275b4e9c40eb314
# murata_l072/README.md "Expected md5s" (13f20aa1, the RS-12.15 reverse-delivery
# fix). Update both when the firmware source changes and the new pair is recorded.
EXPECTED_BENCH_MD5: e083ae46a64686031b39866eca42e094
EXPECTED_PROD_MD5: 148de24e1f9acce417c46c2c69a5be6b
# murata_l072/README.md "Expected md5s" (the RS-12.21 image: scan option (b) +
# L + d2, the firmware park command, the 0x0D split; built 2026-10-25, not yet
# flashed). Update both when the firmware source changes and the new pair is
# recorded.
EXPECTED_BENCH_MD5: 0daae27978089eb97ab35c18718b62b0
EXPECTED_PROD_MD5: 2c5e055abff95126309a62409fafc654
L072_DIR: LifeTrac-v25/DESIGN-CONTROLLER/firmware/murata_l072

jobs:
Expand Down Expand Up @@ -94,13 +96,13 @@ jobs:
echo "| production \`firmware.bin\` | \`$prod\` | README \`$EXPECTED_PROD_MD5\` | $(verdict "$prod" "$EXPECTED_PROD_MD5") |"
echo "| production \`firmware.bin\` | \`$prod\` | committed \`$committed\` | $(verdict "$prod" "$committed") |"
echo
echo "A source change since bb4a2071 moves both README md5s; record the new"
echo "pair in murata_l072/README.md and in this workflow's env."
echo "A source change after the recorded pair moves both README md5s; record"
echo "the new pair in murata_l072/README.md and in this workflow's env."
} >> "$GITHUB_STEP_SUMMARY"
echo "bench built=$bench expected=$EXPECTED_BENCH_MD5"
echo "production built=$prod expected=$EXPECTED_PROD_MD5 committed=$committed"
if [ "$bench" != "$EXPECTED_BENCH_MD5" ]; then
echo "::warning title=L072 bench md5 differs::firmware_bench_diag.bin md5 $bench != README $EXPECTED_BENCH_MD5 (source changed since 13f20aa1, or this Linux build of 12.2.MPACBTI-Rel1 is not byte-identical to the bench PC build)"
echo "::warning title=L072 bench md5 differs::firmware_bench_diag.bin md5 $bench != README $EXPECTED_BENCH_MD5 (source changed after the recorded pair, or this Linux build of 12.2.MPACBTI-Rel1 is not byte-identical to the bench PC build)"
fi
if [ "$prod" != "$EXPECTED_PROD_MD5" ]; then
echo "::warning title=L072 production md5 differs::firmware.bin md5 $prod != README $EXPECTED_PROD_MD5"
Expand Down
22 changes: 22 additions & 0 deletions LifeTrac-v25/DESIGN-CONTROLLER/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,25 @@ None of these decisions is implemented. Each one lists its options and a **RECOM
* **H747 and the X8 link service, PWR-13:** report idle (engine stopped, every valve output off) and hold motion off until the H747 resets or the request is withdrawn. Idle is checked when the reboot is requested; the hold covers motion, not engine start. "Engine stopped" needs an engine-running signal other than the ignition sense I1, and until PWR-12 the H747 reports busy while the key is off. Until this exists the gate blocks every tractor reboot.
* **No systemd-owned hardware watchdog (L2) on the tractor:** a watchdog reset cannot wait for idle. The tractor keeps today's u-boot-armed, kernel-petted WDOG1, so a kernel hang still resets it.
* **LmP's `docker.service` `FailureAction=reboot` goes off on the tractor** (PWR-13): it reboots without waiting for idle. LmP ties it to OTA rollback, so with it off a Docker-breaking update rolls back only through the armed, idle-gated supervisor.

---

## D-FHSS1 — FHSS scan FAILED: no absorbing FAILED for a node without its own clock

**Context:** [firmware/murata_l072/FHSS_SCAN_FAILED_OPTIONS.md](firmware/murata_l072/FHSS_SCAN_FAILED_OPTIONS.md) (the decision memo), TODO RS-12.21 and RS-12.15. On FHSS (profile 1) the base is a follower. Its cold-start scan had four 30 s attempts at a 500 ms dwell; after the fourth it entered scan FAILED, which was absorbing (only a reset or a profile re-activation left it), and a follower in FAILED never LOCKs and never hops. That is the leading hypothesis for leg 6 (2b_f3) of 2026-10-24, where the base never locked and heard 5 of the tractor's 606 frames. The SIL reproduces it against the real firmware and found a tractor twin: in FAILED, one camera stall plus one heard command ends the tractor's self-follow for the session. Walker model: about 7-8 % of 2 fps one-fragment legs end in FAILED, 21-31 % at 1 fps.

| Option | Pros | Cons |
|---|---|---|
| A. A valid frame recovers from FAILED (+ L) | Fastest recovery alone (leg-6 replay median 17.2 s) | Needs the receiver kept armed in FAILED; changes the pure scan policy's contract and the 2026-10-18 leg-X expectations; a foreign transmitter can LOCK a parked base at any time |
| **B. No absorbing FAILED without originator authority, with L (a LOCK re-anchors the 2 s loss timer) and d2 (2 s dwell, the walk continuing across retries and restarts); the firmware park command and the 0x0D fault-code split in the same image** | The normal acquisition path; the pure policy and its vectors unchanged; the tractor twin fixed; no host re-arm needed; leg-6 replay 100/100 (median 17.9 s, 99.8 % heard); 2 fps cold starts not locked by 120 s 6.7 % → 1.3 % | Both boards scan forever once the daemons stop, so the bench park needs the firmware command; continuous RX instead of STANDBY; one 0x0D every 30 s while unacquired; moves the tractor's decay window (below) |
| C. Host watchdog re-sends `REG_PROFILE=1` on a final 0x0D | No flash | Never usable on the tractor (it restarts its grid at epoch 0); FAILED stays absorbing between firings; the tractor twin stays |
| D. A longer dwell alone (d2 or d10) | Fewer cold starts end in FAILED | Does not recover from FAILED (leg-6 replay 0/100) |

**PICK: B** (the memo's section 5 item 2). Picked by Dorkmo on 2026-10-24, with the decay-window trade-off of the memo's section 5 item 3 accepted: in the SIL (SIL-E3, 200 runs; the tractor with 2.5 s camera stalls every 9 s, before any FAILED) the image moves from main's authority on 22.1 % of passes, 53.2 % of commands received and 6.9 own-grid renumberings per run to 14.4 %, 59.1 % and 8.6 per run (each still up to 17 slots). What a renumbering costs the base's camera reception is not modelled. Closing the decay window itself stays the open RS-12.15 grid-policy change. What it means:

* **Scan (`radio/sx1276_rx.c`):** a final FAIL holds FAILED only while the node has originator authority; any other node re-enters SCANNING at once, and a node in FAILED whose authority lapses restarts its scan on its next tick. Every later attempt still sends `RX_SCAN_FAILED` (0x0D) with the final bit, one every 30 s until a LOCK: the 30 s FAIL means "report and keep scanning (receive only)". The pure policy (`radio/sx1276_rx_scan_policy.c`) is unchanged. L: a LOCK starts the 2 s loss timer at the locking frame. d2: `SX1276_RX_SCAN_DWELL_MS` 500 → 2000 ms, a fixed constant (a 50-channel sweep takes 100 s instead of 25 s).
* **Park command (RS-12.21):** `HOST_TYPE_RADIO_PARK_REQ` 0x04, answered by `RADIO_PARK_URC` 0x84 {status 0 PARKED, 1 already parked, 2 refused; RegOpMode readback}. A `host_parked` flag gates every RX arm path and the modem sleeps until a host raw RXCONT write, a profile activation or a reset; a TX_FRAME_REQ while parked gets the ERR_PROTO refusal. VER/READY capability bit 7 (`HOST_CAP_RADIO_PARK`) marks the image.
* **Fault codes:** `RX_SCAN_FAILED` keeps 0x0D and `TX_FIFO_RB_MISMATCH` moves to 0x0F, with a compile-time duplicate check of the `HOST_FAULT_CODE_*` values.
* **Wire versions:** `HOST_PROTOCOL_VER` and `HOST_WIRE_SCHEMA_VER` unchanged: an additive request/URC pair and a fault-code value move, per the 2026-05-19 §13.1 #7 contract; hosts tell the images apart by capability bit 7.
* **Power:** continuous RX instead of STANDBY while unacquired. Fine for the base and the tractor; a battery node would want the back-off that [the 2026-05-19 analysis](../AI%20NOTES/2026-05-19_RX_Scan_FAILED_State_Analysis_Copilot_v1_0.md) §13.2 deferred. This pick replaces that analysis's absorbing-FAILED contract.
* **Status:** implemented 2026-10-25 on branch `fhss-scan-recovery-2026-10-24` and pinned in the SIL (`check-rx-scan-failed-follower`, `check-radio-park`, `check-rx-reverse-delivery`); built (bench `0daae27978089eb97ab35c18718b62b0`, production `2c5e055abff95126309a62409fafc654`), **not flashed**. The flash and the first radio checks (memo section 6.1) each need the operator's GO.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ Properties:
| `0x02` | H→L | `UID_REQ` | request L072 96-bit unique device ID |
| `0x82` | L→H | `UID_URC` | reply with UID |
| `0x03` | H→L | `RESET` | soft reset request (firmware does an orderly NVIC_SystemReset) |
| `0x04` | H→L | `RADIO_PARK_REQ` | firmware radio park (RS-12.21, 2026-10-24): modem to LoRa SLEEP, no RX arm path runs and TX is refused until a raw RXCONT write, a profile activation or a reset; refused while a TX is on air or queued (contract in `host_types.h`) |
| `0x84` | L→H | `RADIO_PARK_URC` | reply: `{status 0 PARKED / 1 ALREADY / 2 REFUSED, RegOpMode readback}` |
| `0x10` | H→L | `TX_FRAME` | transmit a v25 frame; payload is the on-air bytes (already encrypted if H7 owns crypto) plus a small header (channel hint, SF hint, profile hint, priority) |
| `0x90` | L→H | `TX_DONE_URC` | TX completed; payload includes timing metadata |
| `0x91` | L→H | `RX_FRAME_URC` | a frame was received; payload includes radio metadata + bytes |
Expand All @@ -87,7 +89,7 @@ Properties:
| `0x41` | H→L | `STATS_DUMP` | request counter dump |
| `0xC1` | L→H | `STATS_URC` | counter dump payload |
| `0xF0` | L→H | `BOOT_URC` | sent once when the L072 finishes boot; carries safe-mode-was-considered flag, golden-jump-was-considered flag |
| `0xF1` | L→H | `FAULT_URC` | unsolicited fault notification |
| `0xF1` | L→H | `FAULT_URC` | unsolicited fault notification; codes `HOST_FAULT_CODE_*` in `host_types.h` (0x0D RX_SCAN_FAILED; TX_FIFO_RB_MISMATCH moved 0x0D → 0x0F on 2026-10-24, the 0x0D split) |
| `0xFE` | L→H | `ERR_PROTO` | host sent something we don't understand; carries the offending type and ver |
| `0xFF` | both | `RESERVED` | never sent |

Expand Down
Loading
Loading