From d7d6b3ab933935525d80d4b7934bfb362cfdb076 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Sun, 15 Jun 2025 20:19:27 -0500 Subject: [PATCH] updates --- client/src/app.rs | 26 ++++++++++++++------------ client/src/input/inputs.rs | 2 +- client/src/input/keyboard.rs | 9 ++++----- client/src/input/mouse.rs | 28 +++++++++++++++++++--------- scripts/navka-core.sh | 26 ++++++++++++++++---------- 5 files changed, 54 insertions(+), 37 deletions(-) diff --git a/client/src/app.rs b/client/src/app.rs index 82ef0c1..6bcdf3e 100644 --- a/client/src/app.rs +++ b/client/src/app.rs @@ -1,11 +1,14 @@ // client/src/app.rs - +#![forbid(unsafe_code)] use anyhow::Result; +use futures::{FutureExt, StreamExt}; use std::time::Duration; use tokio::{sync::mpsc, sync::broadcast, task::JoinHandle}; +use tokio_stream::StreamExt as _; use tokio_stream::wrappers::{ReceiverStream, BroadcastStream}; use tonic::Request; use tracing::{info, warn, error}; + use navka_common::navka::{relay_client::RelayClient, HidReport}; use crate::input::inputs::InputAggregator; @@ -13,6 +16,7 @@ pub struct NavkaClientApp { aggregator: Option, server_addr: String, dev_mode: bool, + tx: broadcast::Sender, } impl NavkaClientApp { @@ -22,14 +26,16 @@ impl NavkaClientApp { .nth(1) .or_else(|| std::env::var("NAVKA_SERVER_ADDR").ok()) .unwrap_or_else(|| "http://127.0.0.1:50051".to_owned()); - let (tx, _rx) = mpsc::channel::(64); - let mut aggregator = InputAggregator::new(dev_mode, tx); + + let (tx, _) = broadcast::channel::(128); + let mut aggregator = InputAggregator::new(dev_mode, tx.clone()); aggregator.init()?; // discover & grab Ok(Self { aggregator: Some(aggregator), server_addr: addr, dev_mode, + tx, }) } @@ -44,7 +50,7 @@ impl NavkaClientApp { let suicide_future = async { if self.dev_mode { info!("DEV-mode: will kill itself in 30s"); - tokio::time::sleep(std::time::Duration::from_secs(30)).await; + tokio::time::sleep(Duration::from_secs(30)).await; Err::<(), _>(anyhow::anyhow!("dev-mode timer expired - goodbye cruel world...")) } else { futures::future::pending().await @@ -77,7 +83,7 @@ impl NavkaClientApp { }, // reconnect loop _ = self.reconnect_loop() => { - warn!("Reconnect loop ended?? We exit"); + warn!("Reconnect loop ended??"); std::process::exit(0); } } @@ -98,11 +104,8 @@ impl NavkaClientApp { } }; - // fresh channel for aggregator => we do this with new (tx, rx) - let (tx, rx) = mpsc::channel::(64); - let _unused = InputAggregator::new(self.dev_mode, tx.clone()); // TODO: wire this up properly - - let outbound = ReceiverStream::new(rx); + // fresh reader over the *same* broadcast channel + let outbound = BroadcastStream::new(self.tx.subscribe()).filter_map(|r| async { r.ok() }); let response = match client.stream(Request::new(outbound)).await { Ok(r) => r, Err(e) => { @@ -113,7 +116,6 @@ impl NavkaClientApp { }; let mut inbound = response.into_inner(); - // read inbound while let Some(res) = inbound.message().await.transpose() { match res { Ok(report) => { @@ -125,7 +127,7 @@ impl NavkaClientApp { } } } - warn!("Inbound ended. Will try to reconnect in 1s"); + warn!("Diconnected. Inbound ended. Will try to reconnect in 1s"); tokio::time::sleep(Duration::from_secs(1)).await; } } diff --git a/client/src/input/inputs.rs b/client/src/input/inputs.rs index 35148b1..74699c3 100644 --- a/client/src/input/inputs.rs +++ b/client/src/input/inputs.rs @@ -3,7 +3,7 @@ use anyhow::{bail, Context, Result}; use evdev::{Device, EventType, KeyCode, RelativeAxisCode}; use tokio::time::{interval, Duration}; -use tokio::sync::mpsc::Sender; +use tokio::sync::broadcast::Sender; use tracing::{debug, info}; use navka_common::navka::HidReport; diff --git a/client/src/input/keyboard.rs b/client/src/input/keyboard.rs index dd9753a..6e8e7df 100644 --- a/client/src/input/keyboard.rs +++ b/client/src/input/keyboard.rs @@ -2,8 +2,9 @@ use std::collections::HashSet; use evdev::{Device, InputEvent, KeyCode, EventType}; -use tokio::sync::mpsc::Sender; +use tokio::sync::broadcast::Sender; use tracing::{warn, error, info, debug}; + use navka_common::navka::HidReport; use crate::input::keymap::{keycode_to_usage, is_modifier}; @@ -108,10 +109,8 @@ impl KeyboardAggregator { } fn send_report(&self, report: [u8; 8]) { - let _ = self.tx.try_send(HidReport { - kind: Some(navka_common::navka::hid_report::Kind::KeyboardReport( - report.to_vec(), - )), + let _ = self.tx.send(HidReport { + kind: Some(hid_report::Kind::KeyboardReport(report.to_vec())), }); } diff --git a/client/src/input/mouse.rs b/client/src/input/mouse.rs index 6eb6491..8afb259 100644 --- a/client/src/input/mouse.rs +++ b/client/src/input/mouse.rs @@ -1,7 +1,7 @@ // client/src/input/mouse.rs use evdev::{Device, InputEvent, EventType, KeyCode, RelativeAxisCode}; -use tokio::sync::mpsc::Sender; +use tokio::sync::broadcast::Sender; use tracing::{error, debug}; use navka_common::navka::HidReport; @@ -55,13 +55,20 @@ impl MouseAggregator { fn handle_event(&mut self, ev: InputEvent) { match ev.event_type() { - EventType::RELATIVE => { /* fill dx/dy/wheel as i8 */ } - EventType::KEY => { // buttons are REPORTED as KEYS (BTN_LEFT…) + EventType::RELATIVE => { + match RelativeAxisCode::new(ev.code()) { + RelativeAxisCode::REL_X => self.dx = ev.value() as i8, + RelativeAxisCode::REL_Y => self.dy = ev.value() as i8, + RelativeAxisCode::REL_WHEEL => self.wheel = ev.value() as i8, + _ => {} + } + } + EventType::KEY => { let pressed = ev.value() != 0; match ev.code() { - c if c == KeyCode::BTN_LEFT.0 => self.set_btn(0, pressed), - c if c == KeyCode::BTN_RIGHT.0 => self.set_btn(1, pressed), - c if c == KeyCode::BTN_MIDDLE.0=> self.set_btn(2, pressed), + c if c == KeyCode::BTN_LEFT.0 => self.set_btn(0, pressed), + c if c == KeyCode::BTN_RIGHT.0 => self.set_btn(1, pressed), + c if c == KeyCode::BTN_MIDDLE.0 => self.set_btn(2, pressed), _ => {} } } @@ -70,11 +77,14 @@ impl MouseAggregator { // whenever we changed something, emit: let rep = [self.buttons, self.dx as u8, self.dy as u8, self.wheel as u8]; - let _ = self.tx.try_send(HidReport { - kind: Some(navka_common::navka::hid_report::Kind::MouseReport(rep.to_vec())), + let _ = self.tx.send(HidReport { + kind: Some(hid_report::Kind::MouseReport(rep.to_vec())), }); + // reset deltas so we send *relative* movement - self.dx = 0; self.dy = 0; self.wheel = 0; + self.dx = 0; + self.dy = 0; + self.wheel = 0; } } diff --git a/scripts/navka-core.sh b/scripts/navka-core.sh index 867b8f3..80acae3 100644 --- a/scripts/navka-core.sh +++ b/scripts/navka-core.sh @@ -37,21 +37,26 @@ echo "$(cat /proc/sys/kernel/random/uuid)" >"$G/strings/0x409/serialnumber" echo "Navka" >"$G/strings/0x409/manufacturer" echo "Navka Composite" >"$G/strings/0x409/product" -# HID (boot keyboard) +# ----------------------- HID keyboard (usb0) ----------------------- mkdir -p "$G/functions/hid.usb0" echo 1 >"$G/functions/hid.usb0/protocol" echo 1 >"$G/functions/hid.usb0/subclass" echo 8 >"$G/functions/hid.usb0/report_length" -printf '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x01\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x01\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' \ - > "$G/functions/hid.usb0/report_desc" +printf '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01'\ +'\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x01\x95\x05\x75\x01\x05'\ +'\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x01\x95\x06\x75\x08'\ +'\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' \ + >"$G/functions/hid.usb0/report_desc" -# usb1 = mouse +# ----------------------- HID mouse (usb1) -------------------------- mkdir -p "$G/functions/hid.usb1" echo 2 > "$G/functions/hid.usb1/protocol" echo 1 > "$G/functions/hid.usb1/subclass" echo 4 > "$G/functions/hid.usb1/report_length" -printf '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x01\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x01\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' \ - > "$G/functions/hid.usb1/report_desc" +printf '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03'\ +'\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05'\ +'\x01\x09\x30\x09\x31\x15\x81\x25\x7f\x75\x08\x95\x02\x81\x06\xc0\xc0' \ + >"$G/functions/hid.usb1/report_desc" # # -- UAC2 Audio # mkdir -p $G/functions/uac2.usb0 @@ -59,15 +64,16 @@ printf '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01 # echo 2 > $G/functions/uac2.usb0/c_ssize # echo 2 > $G/functions/uac2.usb0/p_chmask -# -- Config +# ----------------------- configuration ----------------------------- mkdir -p "$G/configs/c.1/strings/0x409" echo 500 > "$G/configs/c.1/MaxPower" echo "Config 1" > "$G/configs/c.1/strings/0x409/configuration" -# -- Bindings +# 6) Finally bind to first available UDC ln -s $G/functions/hid.usb0 $G/configs/c.1/ +ln -s $G/functions/hid.usb1 $G/configs/c.1/ # ln -s $G/functions/uac2.usb0 $G/configs/c.1/ -# 6) Finally bind to first available UDC +# 7) Finally bind to first available UDC echo $(ls /sys/class/udc | head -n1) > $G/UDC -echo "[navka-core] gadget ready on USB-C port" +echo "[navka-core] gadget ready (keyboard on hidg0, mouse on hidg1)"