Skip to content

feat(protocol): carry HW revision + FW identity in the MSG_OK_READY ack (CAP-02) - #49

Merged
henols merged 1 commit into
betafrom
fix/hw-revision-gate-ready-ack
Aug 7, 2026
Merged

feat(protocol): carry HW revision + FW identity in the MSG_OK_READY ack (CAP-02)#49
henols merged 1 commit into
betafrom
fix/hw-revision-gate-ready-ack

Conversation

@henols

@henols henols commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Firmware half of the CAP-02 pair. Must land together with henols/firestarter_app#45 — a host on this firmware and a host without it are not interchangeable.

What changed

init_programmer_framed extends the operation-setup ack past CAP-01's 2-byte buffer-size region:

[buffer_size u16 BE][effective_hw_revision u8][ver_len u8][ver bytes]

That is the whole diff — one packed emit replacing LOG_OK_ID_U16(MSG_OK_READY, DATA_BUFFER_SIZE).

Why

The host must refuse to program chips that route VPP to bus line 11 (socket pin 21 on the DIP24_2716 / DIP24_2532 pinouts) unless the attached shield is Rev 2.2 or later — those parts need the 3-position JP4 header, and driving them on an earlier board is a chip-damage path.

The revision was already computed at boot (rurp_detect_hardware_revision() in setup()), but only reachable via a separate CMD_HW_VERSION command or a FLAG_VERBOSE-gated INFO frame. Folding it into MSG_OK_READY lets the host retire its dedicated CMD_FW_VERSION pre-probe, removing one full command exchange per connect.

Notes for review

  • No catalog change, no codegen regen. MSG_OK_READY is already declared params = [{ type = "bytes" }], so the wire shape was already permissive. codegen.py --check confirms the catalog is untouched.
  • The revision byte is always emitted. Builds without HARDWARE_REVISION send 0xFE — the REVISION_UNKNOWN value, spelled as a literal because the symbol itself lives inside that same #ifdef. The ack's shape therefore never varies by build configuration, only by version-string length, and "no detection compiled in" reaches the host as a rejectable value rather than an absent field.
  • Backward compatibility. Hosts predating CAP-02 test len(params) == 2, miss, and fall back to their 512-byte chunk floor: degraded throughput on Leonardo, never a misparse.

Size

target flash before flash after delta static RAM
uno 23954 23988 +34 B unchanged

The 36-byte pack buffer is stack-local to init_programmer_framed, so it does not appear in static RAM — peak stack at that call site grows by ~36 B. Leonardo builds green at 90.9% flash.

Not done

  • No bench validation. The wire format was verified by reading both sides and by host-side unit tests that mirror this packing — never against a real board. This is a safety change; it wants a bench run before it ships.
  • This PR fires no CI. build.yml only triggers on PRs targeting main, and beta-build.yml only on push to beta. Both targets were built locally (pio run -e uno, -e leonardo).

🤖 Generated with Claude Code

CAP-02. The operation-setup ack previously carried only the CAP-01 2-byte
buffer size. It now carries everything the host needs to gate compatibility
at connect time:

  [buffer_size u16 BE][effective_hw_revision u8][ver_len u8][ver bytes]

Motivation: the host must refuse to program chips that route VPP to bus
line 11 (socket pin 21 on the DIP24_2716 / DIP24_2532 pinouts) unless the
attached shield is Rev 2.2 or later -- those parts need the 3-position JP4
header, and driving them on an earlier board is a chip-damage path. The
revision was already computed at boot but only reachable via a separate
CMD_HW_VERSION command or a FLAG_VERBOSE-gated INFO frame.

Folding it into MSG_OK_READY lets the host retire its dedicated
CMD_FW_VERSION pre-probe, removing one full command exchange per connect.

Notes:
- MSG_OK_READY is declared `params = [{ type = "bytes" }]` in the message
  catalog, so this needs NO catalog edit and NO codegen regen.
- The revision byte is always emitted; builds without HARDWARE_REVISION send
  0xFE (the REVISION_UNKNOWN value -- the symbol itself lives inside that
  same #ifdef). The ack's shape therefore never varies by build config, and
  "no detection compiled in" reaches the host as a rejectable value rather
  than as an absent field.
- Hosts predating CAP-02 test `len(params) == 2`, miss, and fall back to
  their 512-byte chunk floor: degraded throughput on Leonardo, never a
  misparse.

Cost: +34 bytes flash on uno (23954 -> 23988), no change to static RAM.
The 36-byte pack buffer is stack-local to init_programmer_framed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@henols henols closed this Aug 7, 2026
@henols henols reopened this Aug 7, 2026
@henols
henols merged commit b1737b2 into beta Aug 7, 2026
1 of 2 checks passed
@henols
henols deleted the fix/hw-revision-gate-ready-ack branch August 7, 2026 14:14
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