From d7fdb2a10fb513ff22e05fd7325bdea0e8affdf3 Mon Sep 17 00:00:00 2001 From: Snoweuph Date: Sun, 5 Jan 2025 23:57:11 +0100 Subject: [PATCH] WIP: Work on Infrastructure to Listen to the Touchinfo --- drivers/simple-cider/Cargo.lock | 86 ++++++++++++++++++++---- drivers/simple-cider/Cargo.toml | 2 +- drivers/simple-cider/Readme.md | 29 ++++++++ drivers/simple-cider/src/main.rs | 11 +-- drivers/simple-cider/src/tb/err.rs | 47 +++++++++++-- drivers/simple-cider/src/tb/imp.rs | 104 +++++++++++++++++++++++++---- drivers/simple-cider/src/tb/mod.rs | 52 ++++++++++++++- 7 files changed, 287 insertions(+), 44 deletions(-) diff --git a/drivers/simple-cider/Cargo.lock b/drivers/simple-cider/Cargo.lock index 60fbd57..2516bdd 100644 --- a/drivers/simple-cider/Cargo.lock +++ b/drivers/simple-cider/Cargo.lock @@ -61,24 +61,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] -name = "hid" -version = "0.4.1" +name = "hidapi" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "526208586d017ea587be6f1c65f6d5491a60d15a6667da110ad2520662a265cb" -dependencies = [ - "hidapi-sys", - "libc", -] - -[[package]] -name = "hidapi-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8a9410aec7ca9f4571ff40c7b1813a28503c2a664a028921fc973073dcd4bf" +checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b" dependencies = [ "cc", + "cfg-if", "libc", "pkg-config", + "windows-sys", ] [[package]] @@ -150,7 +142,7 @@ name = "simple-cider" version = "0.1.0" dependencies = [ "evdev", - "hid", + "hidapi", ] [[package]] @@ -196,6 +188,72 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "wyz" version = "0.5.1" diff --git a/drivers/simple-cider/Cargo.toml b/drivers/simple-cider/Cargo.toml index e028ce4..b538057 100644 --- a/drivers/simple-cider/Cargo.toml +++ b/drivers/simple-cider/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] evdev = "0.12.2" -hid = "0.4.1" +hidapi = "2.6.3" diff --git a/drivers/simple-cider/Readme.md b/drivers/simple-cider/Readme.md index 7a2ac7a..d483889 100644 --- a/drivers/simple-cider/Readme.md +++ b/drivers/simple-cider/Readme.md @@ -1,4 +1,33 @@ # Simple Cider +## Driver Collisions + +The touchbar has a fallback mode, where it is only in Function Mode. +To disable this mode, to not have any collisions with out driver, we should unbind it. + +### Temporary + +run + +```sh +echo -n "1-3:1.2" | sudo tee /sys/bus/usb/drivers/usbhid/unbind +``` + +### Permanent + +create a udev rule: `/etc/udev/rules.d/99-ibridge.rules` + +```udev +SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="8600", ATTR{interfaces}=="*:*:*:*:03:01:01", RUN+="/bin/sh -c 'echo -n $env{BUSNUM}-$env{DEVNUM}:$env{INTERFACE} > /sys/bus/usb/drivers/usbhid/unbind'" +``` + +to apply these rules without reboot run: + +```sh +sudo udevadm control --reload-rules +sudo udevadm trigger +``` + ## Dependencies + - `hidapi-devel` diff --git a/drivers/simple-cider/src/main.rs b/drivers/simple-cider/src/main.rs index db09bbe..7185cb8 100644 --- a/drivers/simple-cider/src/main.rs +++ b/drivers/simple-cider/src/main.rs @@ -5,10 +5,11 @@ use evdev::{Device, Key}; use std::{thread, time}; fn main() -> Result<(), Box> { - let mut device = Device::open("/dev/input/event4")?; - let hid_manager = hid::init()?; + let mut device = Device::open("/dev/input/event14")?; //This changes a lot, need a better way - let mut touchbar = TouchbarImp::new(&hid_manager)?; + let hidapi = hidapi::HidApi::new()?; + + let mut touchbar = TouchbarImp::new(&hidapi)?; let mut fn_key_pressed = false; loop { @@ -16,11 +17,11 @@ fn main() -> Result<(), Box> { if let evdev::InputEventKind::Key(key) = event.kind() { match event.value() { 0 if key == Key::KEY_FN && fn_key_pressed => { - touchbar.set_mode(tb::Mode::Special)?; + touchbar.set_mode(tb::TouchbarMode::Special)?; fn_key_pressed = false; } 1 if key == Key::KEY_FN && !fn_key_pressed => { - touchbar.set_mode(tb::Mode::Function)?; + touchbar.set_mode(tb::TouchbarMode::Function)?; fn_key_pressed = true; } _ => {} diff --git a/drivers/simple-cider/src/tb/err.rs b/drivers/simple-cider/src/tb/err.rs index ff1407b..c397a50 100644 --- a/drivers/simple-cider/src/tb/err.rs +++ b/drivers/simple-cider/src/tb/err.rs @@ -1,20 +1,53 @@ -use std::fmt; +use std::{ + fmt, + sync::{MutexGuard, PoisonError}, +}; + +use hidapi::HidError; + +use super::TouchbarMode; #[derive(Debug)] pub enum TouchbarError { - DeviceNotFound, - CantOpenDevice, - WriteError, + Init(HidError), + PoisionCantChangeMode, + PoisionCantSendEvent, + AlreadyListening, } impl fmt::Display for TouchbarError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - TouchbarError::DeviceNotFound => write!(f, "Touchbar device not found"), - TouchbarError::CantOpenDevice => write!(f, "Cannot open the Touchbar device"), - TouchbarError::WriteError => write!(f, "Error writing to the Touchbar device"), + TouchbarError::PoisionCantChangeMode => write!( + f, + "Unable to Change Mode, because previous thread was posioned" + ), + TouchbarError::PoisionCantSendEvent => { + write!(f, "Unable to Send Event, previous thread was poisioned") + } + TouchbarError::AlreadyListening => { + write!(f, "There is Allready a Listenr Thread running.") + } + TouchbarError::Init(hid_err) => hid_err.fmt(f), } } } impl std::error::Error for TouchbarError {} + +impl From>> for TouchbarError { + fn from(_: PoisonError>) -> Self { + Self::PoisionCantChangeMode + } +} +impl From>> for TouchbarError { + fn from(_: PoisonError>) -> Self { + Self::PoisionCantSendEvent + } +} + +impl From for TouchbarError { + fn from(err: HidError) -> Self { + TouchbarError::Init(err) + } +} diff --git a/drivers/simple-cider/src/tb/imp.rs b/drivers/simple-cider/src/tb/imp.rs index 89815e5..3cf24e0 100644 --- a/drivers/simple-cider/src/tb/imp.rs +++ b/drivers/simple-cider/src/tb/imp.rs @@ -1,34 +1,110 @@ -use crate::tb::{Mode, Touchbar}; +use hidapi::{HidApi, HidDevice}; -use super::TouchbarError; +use super::{TouchbarError, TouchbarEventListener}; +use crate::tb::{Touchbar, TouchbarEvent, TouchbarMediaEvent, TouchbarMode}; +use std::{ + sync::{Arc, Mutex}, + thread::{spawn, JoinHandle}, +}; const TOUCHBAR_VENDOR_ID: u16 = 0x05ac; const TOUCHBAR_PRODUCT_ID: u16 = 0x8600; const TOUCHBAR_MODE_PAYLOAD: u8 = 0x02; +const TOUCHBAR_MAX_PAYLOAD_SIZE: usize = 64; pub struct TouchbarImp { - device: hid::Handle, + device: Arc>, + mode: Mutex, + listeners: Arc>>>, + listener_handle: Option>, + listener_running: Arc>, } impl TouchbarImp { - pub fn new(hid_manager: &hid::Manager) -> Result { - let device = hid_manager - .find(Some(TOUCHBAR_VENDOR_ID), Some(TOUCHBAR_PRODUCT_ID)) - .next() - .ok_or(TouchbarError::DeviceNotFound)?; + pub fn new(hid: &HidApi) -> Result { + Self::from(hid, TouchbarMode::Special) + } - let handle = device.open().map_err(|_| TouchbarError::CantOpenDevice)?; + pub fn from(hid: &HidApi, default_mode: TouchbarMode) -> Result { + let device: HidDevice = hid.open(TOUCHBAR_VENDOR_ID, TOUCHBAR_PRODUCT_ID)?; - Ok(TouchbarImp { device: handle }) + let mut this = TouchbarImp { + device: Arc::new(Mutex::new(device)), + mode: Mutex::new(default_mode), + listeners: Arc::new(Mutex::new(vec![])), + listener_handle: None, + listener_running: Arc::new(Mutex::new(false)), + }; + this.set_mode(default_mode)?; + + Ok(this) } } impl Touchbar for TouchbarImp { - fn set_mode(&mut self, mode: Mode) -> Result<(), TouchbarError> { + fn set_mode(&mut self, mode: TouchbarMode) -> Result<(), TouchbarError> { + let mut mode_guard = self.mode.lock()?; + *mode_guard = mode; + + //TODO: Do real Error handeling here self.device - .data() - .write([TOUCHBAR_MODE_PAYLOAD, mode as u8]) - .map_err(|_| TouchbarError::WriteError)?; + .lock() + .unwrap() + .write(&[TOUCHBAR_MODE_PAYLOAD, mode as u8])?; + Ok(()) } + + fn add_listener(&mut self, listener: Box) { + //TODO: Remove Unwrap with Real Error handeling + self.listeners.lock().unwrap().push(listener); + } + + fn start_listening_input(&mut self) -> Result<(), TouchbarError> { + let mut running = self.listener_running.lock()?; + if *running { + return Err(TouchbarError::AlreadyListening); + } + + *running = true; + + let device = Arc::clone(&self.device); + let running = Arc::clone(&self.listener_running); + let listeners = Arc::clone(&self.listeners); + + self.listener_handle = Some(spawn(move || { + //TODO: Real Error Handeling instead of unwraps + while *running.lock().unwrap() { + //TODO: replace unwrap with real error handeling + + match device + .lock() + .unwrap() + .read(&mut [0u8; TOUCHBAR_MAX_PAYLOAD_SIZE]) + { + Ok(data) => { + //println!("data: {}", data); + //TODO: Parse Event + let event = TouchbarEvent::Media(TouchbarMediaEvent::VolumeUp); + //TODO: remove unwrap with real error Handeling + let listener_lock = listeners.lock().unwrap(); + for listener in listener_lock.iter() { + listener.on_event(event); + } + } + Err(e) => { + //TODO: Real Error Handeling + println!("Error reading data: {:?}", e); + break; + } + } + } + })); + + Ok(()) + } + + fn stop_listening_input(&mut self) -> Result<(), TouchbarError> { + todo!() + } } diff --git a/drivers/simple-cider/src/tb/mod.rs b/drivers/simple-cider/src/tb/mod.rs index 2c976dd..30ae57b 100644 --- a/drivers/simple-cider/src/tb/mod.rs +++ b/drivers/simple-cider/src/tb/mod.rs @@ -1,15 +1,61 @@ mod err; mod imp; + pub use err::*; pub use imp::*; -pub enum Mode { +#[derive(Clone, Copy)] +pub enum TouchbarMode { EscOnly = 0x00, Function = 0x01, Special = 0x02, Off = 0x03, } -pub trait Touchbar { - fn set_mode(&mut self, mode: Mode) -> Result<(), TouchbarError>; +#[derive(Clone, Copy)] +pub enum TouchbarEvent { + Esc, + Function(TouchbarFunctionEvent), + BrightnessDown, + BrightnessUp, + BacklightDown, + BacklightUp, + Media(TouchbarMediaEvent), +} + +#[derive(Clone, Copy)] +pub enum TouchbarFunctionEvent { + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, +} + +#[derive(Clone, Copy)] +pub enum TouchbarMediaEvent { + SkipBack, + PauseResume, + SkipForward, + MuteVolume, + VolumeDown, + VolumeUp, +} + +pub trait TouchbarEventListener: Send { + fn on_event(&self, event: TouchbarEvent); +} + +pub trait Touchbar { + fn set_mode(&mut self, mode: TouchbarMode) -> Result<(), TouchbarError>; + fn add_listener(&mut self, listener: Box); + fn start_listening_input(&mut self) -> Result<(), TouchbarError>; + fn stop_listening_input(&mut self) -> Result<(), TouchbarError>; }