Firmware

Cats capture physical input; the setup's Coordinator interprets it. The Coordinator runs the Input Engine (input-engine: keymap, Vial, pointer, settings, USB HID) and is the tower, or a cat built with the coordinator feature; every other cat is a Satellite that sends over ESP-NOW to the Coordinator's end of the link (coordinator-link: pairing table, sessions, admission, routing into the engine), which a Coordinator cat runs when it is provisioned with a pairing table (naming). Read the composition roots cat/main.rs and tower/main.rs, then follow the types into their modules. Cargo.toml owns the crate boundaries and tools/lx/firmware.sh owns supported build configurations (./lx check --list).

The separate cat/rules, tower/rules, input-engine/rules and coordinator-link/rules crates exist because esp-hal prevents the firmware crates from building on a host. Put deterministic decisions and their tests there; keep peripheral effects in the consuming firmware.

For changes crossing domains, LYNXware.toml owns physical identity, key_index.rs owns matrix conversion, vial.json owns the visual layout, and lynxgram.rs owns default bindings. The latter adapts Arno Klein's Engram layout to these finger and thumb modules.

Operation

Constraints not proved by a host build

  • LYNXware.toml describes the intended fitted modules. The session currently authenticates a cat's role, not its installed variants; role-to-variant admission remains deferred and would require a provisioning or protocol change.
  • Default power policy favors first-key response by keeping the radio alive. radio-teardown trades wake latency for idle power. Neither profile has current measured battery-current figures; do not reuse historical estimates. Light/deep sleep is not implemented on this pinned stack.
  • Mouse deltas stay i16 until HID delivery. The April 2026 bench found sustained ~290-count deltas at 2000 CPI and additional loss during coalescing when the wire was i8; narrowing earlier discarded motion. The accumulator and driver own the current implementation; the PMW3389 driver's header keeps the failed burst-read experiment.
  • The channel candidates include 13 (protocol::CHANNEL_CANDIDATES), permitted in the EU, the target market, but not in the US or Canada. A build for those markets needs another list; the tower cycles through it and a stranded cat scans it, so the whole set is reflashed together.
  • No firmware image carries a third-party blob. The PMW3389's SROM is the builder's own copy, read from its flash sector at boot (firmware/cat/srom); the PMW3610 driver (bm-pmw3610, ported from RMK) needs none and is compile-checked only until its first bench run, as is the ADNS-5050's (bm-adns5050, the v3 module on the PMW wires; USB's 5 V only, so never with battery).

Provisioning and revocation

Provisioning writes a set's secrets over USB; flashing only installs firmware.

Vial settings and diagnostics

In Vial's Keymap → User group, assign a settings keycode to a physical key on any layer, then press it.

Verify battery readings

Build the cat with bat and read its BatteryReport values: the BAT? keycode types the last one per hand on any Coordinator, the T-Dongle shows it on its screen, and a tower-console receiver logs every one (Vial settings).

Link security constraints

The supported design is USB provisioning plus a mutually authenticated session.