33//! `RynkService` is the transport-agnostic core. It holds a
44//! [`KeyboardContext`](super::context::KeyboardContext) and exposes:
55//!
6- //! - [`dispatch`](RynkService::dispatch) — turn one inbound message into
7- //! one outbound message, in-place on the same buffer.
6+ //! - [`dispatch`](RynkService::dispatch) — process inbound message in-place
87//! - [`write_topic`](RynkService::write_topic) — fill a buffer with one
98//! topic message for the per-transport publisher task.
10- //!
11- //! Per-transport adapters (`UsbTransport`, `BleTransport`) live under
12- //! [`transport`] and call `dispatch` inside their own RX/TX loop.
139
1410mod handlers;
1511mod topics;
1612pub mod transport;
1713pub ( crate ) mod wire;
1814
1915use rmk_types:: protocol:: rynk:: { Cmd , RYNK_HEADER_SIZE , RYNK_MIN_BUFFER_SIZE , RynkError , RynkMessage } ;
16+ // TODO: implement and remove this comment
2017// Re-exports used by macro-generated entry code (Phase 6). The `unused`
2118// lint can flip on for feature combos where the macro path isn't compiled —
2219// keep them at the module surface so manually-driven examples still see
@@ -38,126 +35,102 @@ const _: () = assert!(
3835 floor",
3936) ;
4037
41- /// Max packet size to use for the Rynk USB BULK IN/OUT endpoints. 64 B is
42- /// the full-speed maximum and works on every embassy-usb driver; HS-only
43- /// devices can override at the call site for higher throughput.
38+ /// Max packet size to use for the Rynk USB BULK IN/OUT endpoints.
4439#[ cfg( not( feature = "_no_usb" ) ) ]
4540pub const RYNK_USB_MAX_PACKET_SIZE : u16 = 64 ;
4641
47- /// Maximum BLE chunk size that fits in a single GATT write — matches the
48- /// `output_data` characteristic's value-array length in `ble_server.rs`
49- /// (≈ MTU − 3 for the typical 247-byte negotiated MTU).
42+ /// Maximum BLE chunk size that fits in a single GATT write
5043#[ cfg( feature = "_ble" ) ]
5144pub const RYNK_BLE_CHUNK_SIZE : usize = 244 ;
5245
53- /// Transport-agnostic Rynk dispatch core.
54- ///
55- /// Construct via [`RynkService::new`] with a borrowed `KeyMap`. Hand it
56- /// to one or both transports' `run` futures and join the futures into
57- /// the existing `::rmk::run_all!(…)` chain (same pattern Vial uses for
58- /// `host_service.run()`).
46+ /// Transport-agnostic Rynk service.
5947pub struct RynkService < ' a > {
6048 pub ( super ) ctx : KeyboardContext < ' a > ,
6149}
6250
6351impl < ' a > RynkService < ' a > {
64- /// Build a service over a `&KeyMap`. The keymap outlives every
65- /// transport future, so the borrow is sound.
6652 pub fn new ( keymap : & ' a KeyMap < ' a > ) -> Self {
6753 Self {
6854 ctx : KeyboardContext :: new ( keymap) ,
6955 }
7056 }
7157
72- /// Process one inbound message in place: route on `cmd`, let the
73- /// matching handler write the response payload into the same
74- /// buffer, then patch the `LEN` field.
58+ /// Process one inbound message in place.
7559 ///
7660 /// `cmd` and `seq` are echoed verbatim from request to response —
77- /// they're never re-written. The bytes after `RYNK_HEADER_SIZE +
78- /// msg.payload_len()` are unspecified after this returns.
79- ///
80- /// On a malformed header or a topic CMD sent as a request, returns
81- /// `Err(RynkError::InvalidRequest)` and the transport drops the
82- /// message. Handler-level errors are encoded into the payload as
83- /// `Err::<(), RynkError>(e)` and reported as `Ok(())` — every
84- /// legitimate request gets a reply.
85- ///
86- /// Adding a `Cmd`:
87- /// 1. Append the variant in `rmk-types/src/protocol/rynk/cmd.rs`.
88- /// 2. Add the match arm here.
89- /// 3. Add the matching `handle_xxx` method in the relevant
90- /// `handlers/*.rs` file.
61+ /// they're never re-written.
62+ /// The bytes after `RYNK_HEADER_SIZE + msg.payload_len()` are
63+ /// unspecified after this returns.
9164 pub async fn dispatch ( & self , msg : & mut [ u8 ] ) -> Result < ( ) , RynkError > {
9265 let cmd = msg. cmd ( ) ?;
9366
94- let handler_result : Result < usize , RynkError > = match cmd {
67+ let payload_len : usize = match cmd {
9568 // ── System ──
96- Cmd :: GetVersion => self . handle_get_version ( msg. payload_mut ( ) ?) . await ,
97- Cmd :: GetCapabilities => self . handle_get_capabilities ( msg. payload_mut ( ) ?) . await ,
98- Cmd :: Reboot => self . handle_reboot ( msg. payload_mut ( ) ?) . await ,
99- Cmd :: BootloaderJump => self . handle_bootloader_jump ( msg. payload_mut ( ) ?) . await ,
100- Cmd :: StorageReset => self . handle_storage_reset ( msg. payload_mut ( ) ?) . await ,
69+ Cmd :: GetVersion => self . handle_get_version ( msg. payload_mut ( ) ?) . await ? ,
70+ Cmd :: GetCapabilities => self . handle_get_capabilities ( msg. payload_mut ( ) ?) . await ? ,
71+ Cmd :: Reboot => self . handle_reboot ( msg. payload_mut ( ) ?) . await ? ,
72+ Cmd :: BootloaderJump => self . handle_bootloader_jump ( msg. payload_mut ( ) ?) . await ? ,
73+ Cmd :: StorageReset => self . handle_storage_reset ( msg. payload_mut ( ) ?) . await ? ,
10174
10275 // ── Keymap (incl. encoder) ──
103- Cmd :: GetKeyAction => self . handle_get_key_action ( msg. payload_mut ( ) ?) . await ,
104- Cmd :: SetKeyAction => self . handle_set_key_action ( msg. payload_mut ( ) ?) . await ,
105- Cmd :: GetDefaultLayer => self . handle_get_default_layer ( msg. payload_mut ( ) ?) . await ,
106- Cmd :: SetDefaultLayer => self . handle_set_default_layer ( msg. payload_mut ( ) ?) . await ,
107- Cmd :: GetEncoderAction => self . handle_get_encoder_action ( msg. payload_mut ( ) ?) . await ,
108- Cmd :: SetEncoderAction => self . handle_set_encoder_action ( msg. payload_mut ( ) ?) . await ,
76+ Cmd :: GetKeyAction => self . handle_get_key_action ( msg. payload_mut ( ) ?) . await ? ,
77+ Cmd :: SetKeyAction => self . handle_set_key_action ( msg. payload_mut ( ) ?) . await ? ,
78+ Cmd :: GetDefaultLayer => self . handle_get_default_layer ( msg. payload_mut ( ) ?) . await ? ,
79+ Cmd :: SetDefaultLayer => self . handle_set_default_layer ( msg. payload_mut ( ) ?) . await ? ,
80+ Cmd :: GetEncoderAction => self . handle_get_encoder_action ( msg. payload_mut ( ) ?) . await ? ,
81+ Cmd :: SetEncoderAction => self . handle_set_encoder_action ( msg. payload_mut ( ) ?) . await ? ,
10982 #[ cfg( feature = "bulk_transfer" ) ]
110- Cmd :: GetKeymapBulk => self . handle_get_keymap_bulk ( msg. payload_mut ( ) ?) . await ,
83+ Cmd :: GetKeymapBulk => self . handle_get_keymap_bulk ( msg. payload_mut ( ) ?) . await ? ,
11184 #[ cfg( feature = "bulk_transfer" ) ]
112- Cmd :: SetKeymapBulk => self . handle_set_keymap_bulk ( msg. payload_mut ( ) ?) . await ,
85+ Cmd :: SetKeymapBulk => self . handle_set_keymap_bulk ( msg. payload_mut ( ) ?) . await ? ,
11386
11487 // ── Macro ──
115- Cmd :: GetMacro => self . handle_get_macro ( msg. payload_mut ( ) ?) . await ,
116- Cmd :: SetMacro => self . handle_set_macro ( msg. payload_mut ( ) ?) . await ,
88+ Cmd :: GetMacro => self . handle_get_macro ( msg. payload_mut ( ) ?) . await ? ,
89+ Cmd :: SetMacro => self . handle_set_macro ( msg. payload_mut ( ) ?) . await ? ,
11790
11891 // ── Combo ──
119- Cmd :: GetCombo => self . handle_get_combo ( msg. payload_mut ( ) ?) . await ,
120- Cmd :: SetCombo => self . handle_set_combo ( msg. payload_mut ( ) ?) . await ,
92+ Cmd :: GetCombo => self . handle_get_combo ( msg. payload_mut ( ) ?) . await ? ,
93+ Cmd :: SetCombo => self . handle_set_combo ( msg. payload_mut ( ) ?) . await ? ,
12194 #[ cfg( feature = "bulk_transfer" ) ]
122- Cmd :: GetComboBulk => self . handle_get_combo_bulk ( msg. payload_mut ( ) ?) . await ,
95+ Cmd :: GetComboBulk => self . handle_get_combo_bulk ( msg. payload_mut ( ) ?) . await ? ,
12396 #[ cfg( feature = "bulk_transfer" ) ]
124- Cmd :: SetComboBulk => self . handle_set_combo_bulk ( msg. payload_mut ( ) ?) . await ,
97+ Cmd :: SetComboBulk => self . handle_set_combo_bulk ( msg. payload_mut ( ) ?) . await ? ,
12598
12699 // ── Morse ──
127- Cmd :: GetMorse => self . handle_get_morse ( msg. payload_mut ( ) ?) . await ,
128- Cmd :: SetMorse => self . handle_set_morse ( msg. payload_mut ( ) ?) . await ,
100+ Cmd :: GetMorse => self . handle_get_morse ( msg. payload_mut ( ) ?) . await ? ,
101+ Cmd :: SetMorse => self . handle_set_morse ( msg. payload_mut ( ) ?) . await ? ,
129102 #[ cfg( feature = "bulk_transfer" ) ]
130- Cmd :: GetMorseBulk => self . handle_get_morse_bulk ( msg. payload_mut ( ) ?) . await ,
103+ Cmd :: GetMorseBulk => self . handle_get_morse_bulk ( msg. payload_mut ( ) ?) . await ? ,
131104 #[ cfg( feature = "bulk_transfer" ) ]
132- Cmd :: SetMorseBulk => self . handle_set_morse_bulk ( msg. payload_mut ( ) ?) . await ,
105+ Cmd :: SetMorseBulk => self . handle_set_morse_bulk ( msg. payload_mut ( ) ?) . await ? ,
133106
134107 // ── Fork ──
135- Cmd :: GetFork => self . handle_get_fork ( msg. payload_mut ( ) ?) . await ,
136- Cmd :: SetFork => self . handle_set_fork ( msg. payload_mut ( ) ?) . await ,
108+ Cmd :: GetFork => self . handle_get_fork ( msg. payload_mut ( ) ?) . await ? ,
109+ Cmd :: SetFork => self . handle_set_fork ( msg. payload_mut ( ) ?) . await ? ,
137110
138111 // ── Behavior ──
139- Cmd :: GetBehaviorConfig => self . handle_get_behavior_config ( msg. payload_mut ( ) ?) . await ,
140- Cmd :: SetBehaviorConfig => self . handle_set_behavior_config ( msg. payload_mut ( ) ?) . await ,
112+ Cmd :: GetBehaviorConfig => self . handle_get_behavior_config ( msg. payload_mut ( ) ?) . await ? ,
113+ Cmd :: SetBehaviorConfig => self . handle_set_behavior_config ( msg. payload_mut ( ) ?) . await ? ,
141114
142115 // ── Connection ──
143- Cmd :: GetConnectionType => self . handle_get_connection_type ( msg. payload_mut ( ) ?) . await ,
116+ Cmd :: GetConnectionType => self . handle_get_connection_type ( msg. payload_mut ( ) ?) . await ? ,
144117 #[ cfg( feature = "_ble" ) ]
145- Cmd :: GetBleStatus => self . handle_get_ble_status ( msg. payload_mut ( ) ?) . await ,
118+ Cmd :: GetBleStatus => self . handle_get_ble_status ( msg. payload_mut ( ) ?) . await ? ,
146119 #[ cfg( feature = "_ble" ) ]
147- Cmd :: SwitchBleProfile => self . handle_switch_ble_profile ( msg. payload_mut ( ) ?) . await ,
120+ Cmd :: SwitchBleProfile => self . handle_switch_ble_profile ( msg. payload_mut ( ) ?) . await ? ,
148121 #[ cfg( feature = "_ble" ) ]
149- Cmd :: ClearBleProfile => self . handle_clear_ble_profile ( msg. payload_mut ( ) ?) . await ,
122+ Cmd :: ClearBleProfile => self . handle_clear_ble_profile ( msg. payload_mut ( ) ?) . await ? ,
150123
151124 // ── Status ──
152- Cmd :: GetCurrentLayer => self . handle_get_current_layer ( msg. payload_mut ( ) ?) . await ,
153- Cmd :: GetMatrixState => self . handle_get_matrix_state ( msg. payload_mut ( ) ?) . await ,
125+ Cmd :: GetCurrentLayer => self . handle_get_current_layer ( msg. payload_mut ( ) ?) . await ? ,
126+ Cmd :: GetMatrixState => self . handle_get_matrix_state ( msg. payload_mut ( ) ?) . await ? ,
154127 #[ cfg( feature = "_ble" ) ]
155- Cmd :: GetBatteryStatus => self . handle_get_battery_status ( msg. payload_mut ( ) ?) . await ,
128+ Cmd :: GetBatteryStatus => self . handle_get_battery_status ( msg. payload_mut ( ) ?) . await ? ,
156129 #[ cfg( all( feature = "_ble" , feature = "split" ) ) ]
157- Cmd :: GetPeripheralStatus => self . handle_get_peripheral_status ( msg. payload_mut ( ) ?) . await ,
158- Cmd :: GetWpm => self . handle_get_wpm ( msg. payload_mut ( ) ?) . await ,
159- Cmd :: GetSleepState => self . handle_get_sleep_state ( msg. payload_mut ( ) ?) . await ,
160- Cmd :: GetLedIndicator => self . handle_get_led_indicator ( msg. payload_mut ( ) ?) . await ,
130+ Cmd :: GetPeripheralStatus => self . handle_get_peripheral_status ( msg. payload_mut ( ) ?) . await ? ,
131+ Cmd :: GetWpm => self . handle_get_wpm ( msg. payload_mut ( ) ?) . await ? ,
132+ Cmd :: GetSleepState => self . handle_get_sleep_state ( msg. payload_mut ( ) ?) . await ? ,
133+ Cmd :: GetLedIndicator => self . handle_get_led_indicator ( msg. payload_mut ( ) ?) . await ? ,
161134
162135 // Topic CMDs — host shouldn't be sending these.
163136 Cmd :: LayerChange | Cmd :: WpmUpdate | Cmd :: ConnectionChange | Cmd :: SleepState | Cmd :: LedIndicator => {
@@ -169,15 +142,6 @@ impl<'a> RynkService<'a> {
169142 }
170143 } ;
171144
172- let payload_len = match handler_result {
173- Ok ( n) => n,
174- Err ( e) => {
175- let envelope: Result < ( ) , RynkError > = Err ( e) ;
176- postcard:: to_slice ( & envelope, msg. payload_mut ( ) ?)
177- . map ( |s| s. len ( ) )
178- . unwrap_or ( 0 )
179- }
180- } ;
181145 msg. set_payload_len ( payload_len as u16 ) ?;
182146 Ok ( ( ) )
183147 }
@@ -199,3 +163,22 @@ impl<'a> RynkService<'a> {
199163 Ok ( ( ) )
200164 }
201165}
166+
167+ /// Encode a `RynkError` as the response payload (`Result<(), RynkError>::Err(e)`
168+ /// envelope) and patch the header LEN. Transports call this when
169+ /// [`RynkService::dispatch`] returns `Err`, so the host always receives a
170+ /// `Result<T, RynkError>` envelope reply instead of a dropped message.
171+ ///
172+ /// `cmd` and `seq` in the header are left untouched — the host correlates
173+ /// the reply with its outgoing request by `seq`, regardless of the error.
174+ /// Returns `Err(InvalidRequest)` if `msg` itself is shorter than
175+ /// `RYNK_HEADER_SIZE` (i.e. there isn't even room for the header) —
176+ /// transports always pass `RYNK_BUFFER_SIZE` buffers, so this is dead in
177+ /// practice.
178+ pub fn write_error_response ( msg : & mut [ u8 ] , err : RynkError ) -> Result < ( ) , RynkError > {
179+ let envelope: Result < ( ) , RynkError > = Err ( err) ;
180+ let n = postcard:: to_slice ( & envelope, msg. payload_mut ( ) ?)
181+ . map ( |s| s. len ( ) )
182+ . unwrap_or ( 0 ) ;
183+ msg. set_payload_len ( n as u16 )
184+ }
0 commit comments