Skip to content

feat: display-keys no-host idle menu, and a named PIV consent slot - #126

Open
IsayIsee wants to merge 10 commits into
TheMaxMur:mainfrom
IsayIsee:pr/keys-menu
Open

IsayIsee wants to merge 10 commits into
TheMaxMur:mainfrom
IsayIsee:pr/keys-menu

Conversation

@IsayIsee

Copy link
Copy Markdown
Contributor

What

Two changes to the touchless (screen + button) build, and one to the consent
label both screen builds share.

A no-host idle menu. After 30 s with no host configuring the device — a
charger, a bench supply, a dead plug — the STARTING wash becomes a read-only,
single-button browse of the device's own metadata: per-applet counts and slot
states, PIV slot policies, the OpenPGP and OATH listings, one row per passkey
relying party (a hold opens its account list), backup state and firmware
identity, plus a SETTINGS page for the menu entry delay and the screen
direction (the USB-C plug is reversible). Taps step, a double steps back, a
hold opens a level. The only flash it writes is its own settings record, and
plugging into a host leaves the menu immediately.

PIV's touch consent names the slot it is asking for (9A Auth,
Retired #1, …) rather than one generic title. Both screen builds take the
label from one function, rsk_piv::info::slot_label.

Why the menu's config is a record of its own

The menu persists two settings (entry delay, screen direction) in EF_MENU_CONF
(0xE031) rather than in two spare bits of the touch build's EF_DISPLAY
(0xE030), which has six unused bits today:

  • Ownership. EF_DISPLAY belongs to rsk-display, which this build
    deliberately does not pull in (it shares only display_panel). Its writer is
    a single function whose stated job is carrying the flags it knows; a flip bit
    it has never heard of would be cleared by the first touch-build boot after a
    reflash, and fixing that would mean editing the touch build's write path for
    a setting it does not have.
  • Precedent. EF_LED_CONF, EF_PHY, EF_HARDENED and EF_DEV_CONF are
    per-concern records in the same style; 0xE0xx is the display-config area, so
    a factory reset clears this one exactly as it clears EF_DISPLAY.
  • Compatibility. A missing record, a shorter one from an older build, or a
    delay index this build does not list decodes to that field's default (30 s,
    no flip) instead of refusing the boot — the codec is in rsk-ui beside the
    touch build's settings_store, with the decoding rules pinned by tests.

Notes

  • rsk_piv::info::slot_label is deliberately duplicated in rsk-ui's PIV
    detail screens (which may not depend on rsk-piv); both copies carry a
    comment saying so.
  • bcdDevice moves to 0x09DC. This branch is stacked on the touchless
    display build (feat: touchless display build for screen+button boards (display-keys) #123) — if that lands first this is one bump above it, and if
    it lands second the same applies in reverse.

IsayIsee added a commit to IsayIsee/RS-Key that referenced this pull request Sep 24, 2026
`docs/releases.md`'s `display-keys` row sends a reader to
`guides/display.md`, and the guide had nothing to say about the touchless
build: the one-key flow lived only in the README and the CHANGELOG.

- `guides/display.md`: a "The touchless variant" section — ambient status,
  the confirm page naming the pending operation, a short press against the
  ~0.8 s hold, PINs host-side — with the See-also line naming both features.
- `hardware.md`: the board beside the touch one, photo and label.
- `build.md`: the feature's own row and `waveshare-geek` in the `BOARD`
  list, which is what the See-also line now points at.

The `display-keys` matrix row also stops advertising the no-host idle menu,
which this PR does not build; the menu PR restores the mention (TheMaxMur#126).

Docs only: no `bcdDevice` move, no wire surface.
@github-actions

Copy link
Copy Markdown

Development firmware for this pull request: https://rskey.fob.wtf/preview?pr=126

The link always opens the latest successful preview build.

Waveshare RP2350-GEEK is the first target: a 1.14" 240x135 ST7789V2 panel
over the shared PIO transport, driven by one physical button. The screen shows
the ambient status, a trusted one-key confirm page naming the pending
operation, and approve/decline feedback; a short press approves, a hold past
0.8 s declines. No touch pad means no on-device PIN entry, so `uv` stays
unadvertised and the CCID pinpad stays off — PINs are host-side, as on a
button-only key.

`display-keys` is a cargo feature parallel to `display` (the two are
`compile_error!`-exclusive) and shares only `display_panel`; `rsk-display`,
`rsk-bip39`, `rsk-slip39` and the touch flow are not pulled in. The arbitration
the new build waits on is host-tested: `rsk_device::presence::GestureWait`
carries the same `spent` latch and scoped cancel as `ButtonWait`, with unit
tests and Kani proofs beside it — which is what moves the
`BugNoDropStaleCancelAtEntry` comutant's anchor onto the `wait` signature, the
two entry preambles now being identical.

The partial glass needs board keys: `display.madctl_scan`, `display.win_x` and
`display.win_y` (all default 0, so every existing board is unchanged) plus the
full ST7789V2 init register set and a GRAM blank before display-on, without
which the 240x135 frame lands on the controller's larger GRAM and is clipped.
The GEEK board file and the `firmware-display-keys` nix package (with the
`-strong-pin` / `-always-uv` posture variants the default board has) join the
release matrix, fourteen flavors become seventeen; `bcdDevice` moves to 0x09DB.

The assurance matrix gains the four new columns as `gap` cells with settling
questions, the pages the new code moved are regenerated, and the citations are
re-locked.
`display_keys.rs`: the nested `if let` collapses into a let-chain, and the two
divisibility tests (`% 2 == 0`, `% 3 == 0`) become `is_multiple_of`. These are
what the gate's clippy reports; no other file changes.
`docs/releases.md`'s `display-keys` row sends a reader to
`guides/display.md`, and the guide had nothing to say about the touchless
build: the one-key flow lived only in the README and the CHANGELOG.

- `guides/display.md`: a "The touchless variant" section — ambient status,
  the confirm page naming the pending operation, a short press against the
  ~0.8 s hold, PINs host-side — with the See-also line naming both features.
- `hardware.md`: the board beside the touch one, photo and label.
- `build.md`: the feature's own row and `waveshare-geek` in the `BOARD`
  list, which is what the See-also line now points at.

The `display-keys` matrix row also stops advertising the no-host idle menu,
which this PR does not build; the menu PR restores the mention (TheMaxMur#126).

Docs only: no `bcdDevice` move, no wire surface.
After 30 s with no host configuring the device, the touchless build's STARTING
wash becomes a read-only, single-button browse of the device's own metadata —
per-applet counts and slot states, PIV slot policies, the OpenPGP and OATH
listings, one row per passkey relying party, backup state and firmware
identity — plus a SETTINGS page for the menu entry delay and the screen
direction (the USB-C plug is reversible). The only flash it writes is its own
record, and plugging into a host leaves the menu immediately.

PIV's touch consent now names the slot it asks for (`9A Auth`, `Retired #1`,
…) rather than one generic title, and both screen builds take the label from
one function (`rsk_piv::info::slot_label`) instead of each spelling the same
vocabulary.

The menu's config is `EF_MENU_CONF` (`0xE031`), a record of its own: the touch
build's `EF_DISPLAY` belongs to `rsk-display`, which this build does not pull
in, and that crate's single writer carries only the flags it knows — a flip bit
it has never heard of would be cleared by the first touch-build boot after a
reflash. The codec lives in `rsk-ui` beside `settings_store`, with the decoding
rules (a missing record, a shorter one from an older build, an index this build
does not list) pinned by tests.

`bcdDevice` moves to 0x09DC.
`docs/releases.md`'s `display-keys` row names the no-host idle menu again:
the previous PR dropped the mention because it did not build the screen, and
this one does.

`guides/display.md`'s touchless section gains the paragraph the README and
the CHANGELOG already carry — what the menu shows, `Taps step next, a double
steps back, a hold opens a level`, the SETTINGS page's two knobs, and that the
only flash it writes is its own record.

Docs only: no `bcdDevice` move.
…ollow

The branch stacks on TheMaxMur#123 and inherits its gate failure: `display` and
`display-keys` both stole the panel pads with the same five tokens, so
`site_keys()` had no sequence to tell them apart and fell back to a
positional `~2`. The same `panel_pad` helper lands here, as an equivalent
change rather than a rebase — neither branch needs the other to build.

The menu's own bump sits on top of the parent's 0x09DC:

- `device_release` 0x09DD, with both CHANGELOG entries: the helper as
  `refactor, no behaviour change`, the menu as the behaviour change it is —
  a new flavor to build, a new settings record, a new screen.
- `assurance/platform.toml` (PLAT-UNSAFE-004's ninth cover, plus
  PLAT-UNSAFE-013), `docs/unsafe.md` (Runtime sites 24) and
  `docs/platform-assumptions.md`: the audit surface TheMaxMur#123 moves, over this
  tree's line numbers.
- `formal/citations.lock` and `assurance/board/PLAT-TIMER-00{2,3}.toml`: the
  line numbers the menu code and the two bumps moved.
`AnyPin::steal` hands back `Peri<'static, AnyPin>`, so a helper declared
`-> AnyPin` erased the token `Output::new` needs. Only the `display-keys`
flavor compiles through the helper — the `display` build passes the same
expression inline, where nothing erases it.
… build

`AnyPin::steal` hands back `Peri<'static, AnyPin>`, so a helper declared
`-> AnyPin` erased the token `Output::new` needs. Only the `display-keys`
flavor compiles through the helper — the `display` build passes the same
expression inline, where nothing erases it. A line that can reach the image
owes the bump, so `bcdDevice` moves to 0x09DE.
The `display-keys` packages and the `waveshare-geek` board took the matrix
from 31 configurations to 35 and its 1240 cells to 1400 (37 covered, 143
equivalent, 109 out-of-scope, 1111 gap). The eleven slices kept the old
line, so `bundle_gate` read 88 stale transcriptions and the check job
stopped on its row; the cases pinning the same numbers were stale with it,
and the generated page carried the pre-board input counts.

Gate, tests and docs only: `assurance/`, `scripts/` and `docs/` carry no
line the image is built from, so no `bcdDevice` bump.
The `waveshare-geek` board and its three `display-keys` packages took the
matrix from 19 flake packages to 22 and its boards from 6 to 7, and the
touchless build added a ninth `AnyPin::steal` site, a thirteenth PLAT-UNSAFE
row and a ninth `cargo doc` row. Four pins still held the pre-board counts,
so `pytest (gate scripts)` read three failures — `matrix_gate.FLOOR_PACKAGES`
at 19 against a derivation of 22, `len(steals)` at 8 against 9, and the
`cargo doc` row count at 8 against 9 — and the check job stopped on its row.
The floors sit AT the count by design (upstream's `583e58eb`), and this PR's
own `docs/unsafe.md` already numbers the ninth steal — ×8 → ×9 — so the pins
were stale, not the tree.

The prose carrying the same counts follows them, in the same diff: the
`matrix_gate` docstring and the matrix page's template sentence, that page
regenerated with `--write`; `docs/formal.md`'s sentence naming packages,
features and boards; `check.sh`'s comment on the matrix row; the two test
comments quoting the old figures; and `PLAT-TOOLCHAIN-002`'s statement,
discharge and header comment, which still counted twelve rows over
thirty-one sites with eight of them GPIO steals — its page regenerated with
`--write` as well. `12 against 19` stays where it is: that is the history of
where the floor came from, not a count of this tree.

Gate, tests and docs only: `scripts/`, `docs/` and `assurance/` carry no line
the image is built from, so no `bcdDevice` bump.
IsayIsee added a commit to IsayIsee/RS-Key that referenced this pull request Oct 19, 2026
`docs/releases.md`'s `display-keys` row sends a reader to
`guides/display.md`, and the guide had nothing to say about the touchless
build: the one-key flow lived only in the README and the CHANGELOG.

- `guides/display.md`: a "The touchless variant" section — ambient status,
  the confirm page naming the pending operation, a short press against the
  ~0.8 s hold, PINs host-side — with the See-also line naming both features.
- `hardware.md`: the board beside the touch one, photo and label.
- `build.md`: the feature's own row and `waveshare-geek` in the `BOARD`
  list, which is what the See-also line now points at.

The `display-keys` matrix row also stops advertising the no-host idle menu,
which this PR does not build; the menu PR restores the mention (TheMaxMur#126).

Docs only: no `bcdDevice` move, no wire surface.

This branch has not been deployed

No deployments
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