feat(sim): add 2026.8.3 message variants for a 2026 DIR/PMR #24

Merged
outlandnish merged 2 commits from feat/sim-2026-fw-variant into main 2026-09-12 08:55:24 -05:00
Owner

Adds 2026.8.3 fw_variants so the sim can drive a 2026 DIR/PMR. 2020/2022 targets are byte-identical.

Derived from the gen-28 2022 vs 2026 DIR rx sets (enumerated from the checkRxDlc call sites — the frame ID is a literal argument) plus both ETH DBCs.

Node Change
BMS 0x132 → DLC 6; 0x212 hvState @16→@60; 0x252 powerLimitsState @48→@42
UI 0x284 gains counter@52 + checksum@56; adds 0x238, 0x3FD
VCFRONT 0x3A1 checksum seed 0x2A → 0xC0
APP 0x25C → 0x25B, DLC 1→8, gated, seed 0x5B
VCLEFT adds 0x142
GTW adds 0x318

Three things the DBC does not tell you:

  • DLC is an exact match in firmware, not a minimum. checkRxDlc returns 1 only when actual == expected; both short and long frames are rejected. So 0x132 8→6 is a hard break, not cosmetic.
  • 0x3A1's checksum seed was reseeded again: 0xA4 (2020) → 0x2A (2022) → 0xC0 (2026). It is a vcfrontMIA member, so a stale seed presents as an MIA on a frame that looks perfectly healthy on the wire. Swept the seed out of all 17 gated frames: 15 use id_lo + id_hi, only 0x3A1 and 0x25B deviate — hence SimFrame.cksum_magic / place_checksum(magic_value).
  • 0x25C → 0x25B is a renumber, not a deletion — the app-liveness frame behind appMIA a108. 0x25C is the only id the 2026 DIR dropped.

The four other frames 2026 adds (0x142, 0x238, 0x318, 0x3FD) are all MIA-supervised, so they are sent as zeros(8) liveness for the same reason 0x3B3 is on 2022 — arrival is what clears the MIA, and optional-node MIA bites in DRIVE, which is where a spin test lives. Zeros are checked against the handlers rather than assumed: 0x142 and 0x3FD clear their MIA bit inside (word0 & 3) == 0 / (word0 & 7) == 0, which zeros satisfy; 0x238 and 0x318 clear unconditionally once validation passes. Both gated ones use the default id_lo + id_hi seed.

0x1D5 PMF_state4 and 0x2E5 DIF_power are also new to the 2026 DIR but are AWD-only — confirmed against a same-rev gen-32 RWD/AWD PMR pair — so they stay unsimulated.

Scaling is unchanged (no BMS LSB moved 2022→2026), so _SCALE_2022 carries forward and the a125 calibration still holds.

Golden tests encoded "only 2022 variants exist" and "nothing is dropped going forward"; 2026 makes the latter false. Updated to be revision-aware, with a guard that a 2022 bench still resolves to the 2022 set.

Verified by re-deriving the frame bytes against the firmware rules rather than just the wiring: 0x212 byte7 0x01→0x31, 0x3A1 byte7 shifted by exactly 0xC0-0x2A, 0x238/0x318 checksums 0x3a/0x1b, counters increment, 2022 path byte-identical. 3203 tests pass, ruff clean.

Untested on hardware — needs a bench run against a 2026 DU (watch appMIA a108, vcfrontMIA a155, uiMIA a088).

Background: docs/private/dir-pmr-can-delta-2022-to-2026.md.

🤖 Generated with Claude Code

Adds `2026.8.3` `fw_variants` so the sim can drive a 2026 DIR/PMR. 2020/2022 targets are byte-identical. Derived from the gen-28 2022 vs 2026 DIR rx sets (enumerated from the `checkRxDlc` call sites — the frame ID is a literal argument) plus both ETH DBCs. | Node | Change | |---|---| | BMS | `0x132` → DLC 6; `0x212` hvState `@16`→`@60`; `0x252` powerLimitsState `@48`→`@42` | | UI | `0x284` gains counter@52 + checksum@56; adds `0x238`, `0x3FD` | | VCFRONT | `0x3A1` checksum seed `0x2A` → `0xC0` | | APP | `0x25C` → `0x25B`, DLC 1→8, gated, seed `0x5B` | | VCLEFT | adds `0x142` | | GTW | adds `0x318` | Three things the DBC does not tell you: - **DLC is an exact match in firmware, not a minimum.** `checkRxDlc` returns 1 only when `actual == expected`; both short and long frames are rejected. So `0x132` 8→6 is a hard break, not cosmetic. - **`0x3A1`'s checksum seed was reseeded again:** `0xA4` (2020) → `0x2A` (2022) → `0xC0` (2026). It is a vcfrontMIA member, so a stale seed presents as an MIA on a frame that looks perfectly healthy on the wire. Swept the seed out of all 17 gated frames: 15 use `id_lo + id_hi`, only `0x3A1` and `0x25B` deviate — hence `SimFrame.cksum_magic` / `place_checksum(magic_value)`. - **`0x25C` → `0x25B` is a renumber, not a deletion** — the app-liveness frame behind appMIA a108. `0x25C` is the only id the 2026 DIR dropped. The four other frames 2026 adds (`0x142`, `0x238`, `0x318`, `0x3FD`) are all MIA-supervised, so they are sent as `zeros(8)` liveness for the same reason `0x3B3` is on 2022 — arrival is what clears the MIA, and optional-node MIA bites in DRIVE, which is where a spin test lives. Zeros are checked against the handlers rather than assumed: `0x142` and `0x3FD` clear their MIA bit *inside* `(word0 & 3) == 0` / `(word0 & 7) == 0`, which zeros satisfy; `0x238` and `0x318` clear unconditionally once validation passes. Both gated ones use the default `id_lo + id_hi` seed. `0x1D5 PMF_state4` and `0x2E5 DIF_power` are also new to the 2026 DIR but are AWD-only — confirmed against a same-rev gen-32 RWD/AWD PMR pair — so they stay unsimulated. Scaling is unchanged (no BMS LSB moved 2022→2026), so `_SCALE_2022` carries forward and the a125 calibration still holds. Golden tests encoded "only 2022 variants exist" and "nothing is dropped going forward"; 2026 makes the latter false. Updated to be revision-aware, with a guard that a 2022 bench still resolves to the 2022 set. Verified by re-deriving the frame bytes against the firmware rules rather than just the wiring: `0x212` byte7 `0x01`→`0x31`, `0x3A1` byte7 shifted by exactly `0xC0-0x2A`, `0x238`/`0x318` checksums `0x3a`/`0x1b`, counters increment, 2022 path byte-identical. 3203 tests pass, ruff clean. Untested on hardware — needs a bench run against a 2026 DU (watch appMIA a108, vcfrontMIA a155, uiMIA a088). Background: `docs/private/dir-pmr-can-delta-2022-to-2026.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(sim): add 2026.8.3 message variants for a 2026 DIR/PMR
Some checks failed
Tests / test (pull_request) Has been cancelled
85b694dbf3
Derived from the gen-28 2022 vs 2026 DIR rx sets (enumerated from the
checkRxDlc call sites) plus both ETH DBCs:

- BMS 0x132 -> DLC 6. The DIR's DLC check is an EXACT match, not a
  minimum, so the 8-byte build is rejected outright on 2026.
  0x212 hvState @16|3 -> @60|3 (+chargeRequest @29 -> @30);
  0x252 powerLimitsState @48 -> @42.
- UI 0x284 gains counter@52 + checksum@56. 2022 validated neither; 2026
  enforces both, and a failure drops the frame exactly like a DLC
  mismatch -- taking UI_serviceMode, and the learn routines, with it.
- VCFRONT 0x3A1 checksum seed 0x2A -> 0xC0. Reseeded again in 2026
  (0xA4 in 2020). A vcfrontMIA member, so a stale seed shows up as an
  MIA on a frame that looks healthy on the wire.
- APP 0x25C -> 0x25B, DLC 1 -> 8, gated, seed 0x5B. A renumber of the
  app-liveness frame, not a deletion; 0x25C is the only id the 2026 DIR
  dropped.

SimFrame.cksum_magic + place_checksum(magic_value) because the seed is
not purely a function of the ID -- 15 of 17 gated frames use
id_lo + id_hi, 0x3A1 and 0x25B do not.

Scaling is unchanged: no BMS LSB moved between 2022 and 2026, so
_SCALE_2022 carries forward and the a125 calibration still holds.
2020/2022 targets are byte-identical.

Two golden tests encoded "only 2022 variants exist" and "nothing is
dropped going forward"; 2026 makes the latter false. Updated to be
revision-aware, with a guard that a 2022 bench still resolves to the
2022 set.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat(sim): send the 2026-new MIA members too
Some checks failed
Tests / test (pull_request) Has been cancelled
cd6ca84299
All four frames 2026 adds to the DIR's rx set are MIA-supervised (each
clears a bit in the DIR's MIA words), so leaving them out left holes in
the aggregates. Optional-node MIA is drive-state gated -- it bites in
DRIVE, which is exactly where a spin test lives -- so they are sent for
the same reason 0x3B3 is on 2022: arrival is what clears the MIA.

  VCLEFT 0x142 VCLEFT_liftgateStatus   ungated
  UI     0x238 UI_driverAssistMapData  gated, ctr@52 cks@56, magic 0x3A
  GTW    0x318 GTW_carState            gated, ctr@52 cks@56, magic 0x1B
  UI     0x3FD UI_autopilotControl     ungated

All zeros(8), checked against the handlers rather than assumed: 0x142
and 0x3FD clear their MIA bit INSIDE (word0 & 3) == 0 and
(word0 & 7) == 0 respectively, which a zero payload satisfies; 0x238 and
0x318 clear unconditionally once validation passes. No decoded field
feeds the torque path -- 0x238's has exactly one xref in the image, its
own writer.

Both gated frames use the default id_lo + id_hi seed, so no new
cksum_magic override is needed.

0x1D5 PMF_state4 and 0x2E5 DIF_power are also new to the 2026 DIR but
are AWD-only (confirmed against a same-rev gen-32 RWD/AWD PMR pair), so
they stay unsimulated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
outlandnish/tm3diag!24
No description provided.