Add bounded split application messages - #984
Draft
colonelpanic8 wants to merge 21 commits into
Draft
Conversation
Replace the placeholder rmk protocol module with the Rynk wire format: command, endpoint, and topic tables, error and message types, layout and system payloads, plus wire snapshots. Add tsify-based TypeScript type generation for host reuse.
…[keymap.layer]] Separate the physical key map from the keymap: drop the legacy matrix_map/keymap path and its codegen, and add the macro codegen for the new schema.
… handler Route USB and BLE host access through one handler and replace the vial_lock feature with host_lock.
Includes the lock gate, device-info and layout-blob endpoints, and keymap bulk transfer across layer boundaries.
Generates the TypeScript type bindings consumed by the web demo.
… examples Add rp2040_rynk and qemu-riscv-rynk, adapt example sources, and regenerate Cargo.lock files.
Signed-off-by: Haobo Gu <haobogu@outlook.com>
Store each tap-hold's timing profile as a u8 index into a small, deduplicated `taphold_profiles` table rather than an inline 4-byte `MorseProfile`. `KeyAction::TapHold` shrinks from 12 to 7 bytes, which also drops the u32's 4-byte alignment padding across every KeyAction-sized RAM buffer (keymap array, held-key buffer, combos, forks, morse cache). Measured on the nrf52840 example at a 5x14x5 (350-key) board: .bss -2408 bytes, .text -4 bytes (no flash cost). Savings scale with board size; the table cost (CAP*4, default CAP=16 -> 64 B) is fixed. - keyboard.toml: named profiles are interned automatically by the proc-macro; users keep referencing them by name. - pure-Rust: default macros (th!/mt!/lt!/tt!) are unchanged; the custom-profile macros (thp!/mtp!/ltp!/ttp!) now take a table index and the user populates `behavior.morse.taphold_profiles`. - Table capacity is configurable via `[rmk] taphold_profile_max_num`. - Vial wire format is unchanged (profile isn't carried); the stored KeyAction encoding changes but auto-migrates via the build-hash guard. Regenerated the rmk_protocol keymap endpoint snapshots (KeyAction schema change propagates to keymap/combo/encoder/fork endpoints).
* refactor: redesign core rynk traits, achieve full-duplex communication Signed-off-by: Haobo Gu <haobogu@outlook.com> * refactor: update rynk crates to use the new contract Signed-off-by: Haobo Gu <haobogu@outlook.com> * chore(rynk): trim comments * refactor(rynk): third simplification pass - rynk-wasm: drop the label round-trip (JS already owns the picker name) and the WebDevice wrapper — JsByteLink is a local wasm-bindgen type, so it implements RynkDevice directly; device.rs deleted - qemu_behavior: drop six request_raw calls duplicating the typed calls right above them (request delegates to request_raw, same code path) - driver/tests: drop three tests subsumed by supersets (cmd mismatch, topic-during-request, cancelled-request recovery) - rynk-serial: declare the tokio feature actually used (io-util, not time) Signed-off-by: Haobo Gu <haobogu@outlook.com> --------- Signed-off-by: Haobo Gu <haobogu@outlook.com>
Signed-off-by: Haobo Gu <haobogu@outlook.com>
Rebasing onto origin/main linearized away the merge commit 9b8d64c, which carried hand-made changes not present in either parent: the nrf54lm20_ble example tweaks, the rynk_loopback fixture downsize, and the rynk/Cargo.lock removal. Restore them to match the pre-rebase tree.
Signed-off-by: Haobo Gu <haobogu@outlook.com>
- features/rynk.md: drop the non-existent `bulk` Cargo feature (the `features = ["bulk"]` snippet failed to compile); bulk is always on with `rynk`, sized by `rynk_buffer_size`. Note the tool-author example needs `embassy-futures`. - migration/v08_v09.md: fix the fabricated `bulk_transfer` -> `bulk` rename (removed, folded into `rynk`); document the `KeyAction::TapHold` u8-index break, the removed `[rmk].protocol_max_bulk_size` key, and the new unknown-key strictness. - configuration/layout.md: remove the `PDF(n)` action (unsupported in keyboard.toml — the keymap grammar has no rule for it), document the `Trns` transparent form, and split two examples that shared one toml fence. - rmk/CHANGELOG.md: add the Rynk feature entry and the BREAKING `keyboard.toml` layout-schema change.
A USB bulk-IN transfer completes on the host only once it sees a packet shorter than the max packet size. A device-to-host frame whose length is a multiple of that size (64 at Full-Speed) ends on a full packet, so the host read stays pending. Wrap the CDC Sender in a small Write adapter that appends a zero-length packet after such a frame. Scoped to the USB transport; run_session, UART, and BLE are untouched. This is an independent robustness fix, not the root cause of the nRF52840 "CDC IN never completes" report — there even the short handshake response and raw libusb hung, which a ZLP cannot explain. Signed-off-by: Haobo Gu <haobogu@outlook.com>
Add an opaque, bounded application payload that firmware can exchange between the split central and peripheral alongside the normal split traffic, without ever taking priority over key events. * `split_app` module: `SplitAppData` (a small, `MaxSize`, postcard length-prefixed payload) plus four statics — `SPLIT_APP_TX` (central -> peripheral), `SPLIT_APP_PERIPH_TX` (peripheral -> central), the symmetric `SPLIT_APP_RX` inbox, and the `SPLIT_APP_LINK` watch that reports split-link state to the application. * Producers use `try_send` only (bounded, drop-on-full) so the split read/write loops never block or get starved by application traffic; key events are always polled first. * The split driver and peripheral drain the application queues as the lowest-priority arm of their outgoing selects and forward received `SplitMessage::Application` payloads into the inbox. * `SPLIT_APP_LINK` is state-based (a `Watch`), so a late-subscribing application still observes the current link state; the `false -> true` edge is a resync trigger. Link-down edges are emitted from a drop guard so they survive async cancellation of the split session. * On the peripheral the link is raised on the FIRST inbound message from the central rather than on bare connection: over BLE, notifications to a central that has not yet subscribed are silently dropped, so the connection alone is not proof the application channel is usable. Developed for a split keyboard port.
colonelpanic8
marked this pull request as draft
July 20, 2026 22:49
Contributor
|
Iirc this is also useful to transport state of the keyboard to the peripheral that is not available in the usual split protocol right? Like for example I have a special function in my firmware that moves the mouse pointer a bit automatically when it's active. And I have a display on the peripheral that should display whether it's active. |
HaoboGu
force-pushed
the
feat/rynk
branch
5 times, most recently
from
July 31, 2026 14:10
c09015e to
d2c97ab
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Why
RMK-based firmware sometimes needs to coordinate application-owned state across halves without adding hardware-specific meaning to the core split protocol. Per-key lighting is one consumer, but this API stays opaque and allocation-free.
Impact
Existing split behavior is unchanged unless the new queues are used. The implementation currently targets a single split peripheral and documents that limitation.
Checks