From 5cc1571acfc751e2949ebfd0825b75c612137439 Mon Sep 17 00:00:00 2001 From: "Derek J. Clark" Date: Fri, 26 Apr 2024 20:38:28 -0700 Subject: [PATCH] fix(Manager): Use loop to check for IIO devices as inotify doesn;t work on sysfs. --- src/input/manager.rs | 193 +++++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 79 deletions(-) diff --git a/src/input/manager.rs b/src/input/manager.rs index 6ca9384..56d4d6c 100644 --- a/src/input/manager.rs +++ b/src/input/manager.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::error::Error; use std::fs; +use std::time::Duration; use tokio::sync::broadcast; use tokio::sync::mpsc; @@ -33,6 +34,7 @@ use crate::input::target::xb360::XBox360Controller; use crate::input::target::TargetDeviceType; use crate::procfs; use crate::watcher; +use crate::watcher::WatchEvent; use super::composite_device::Handle; use super::target::TargetCommand; @@ -1086,14 +1088,75 @@ impl Manager { // Create a channel to handle watch events let (watcher_tx, mut watcher_rx) = mpsc::channel(BUFFER_SIZE); + log::debug!("Performing initial input device discovery"); + Manager::discover_human_interface_devices(&watcher_tx).await?; + Manager::discover_event_devices(&watcher_tx).await?; + Manager::discover_iio_devices(&watcher_tx).await?; + log::debug!("Initial input device discovery complete"); + + // Start a task to dispatch filesystem watch events to the `run()` loop + let cmd_tx = self.tx.clone(); + tokio::spawn(async move { + log::debug!("Dispatching filesystem watch events"); + while let Some(event) = watcher_rx.recv().await { + log::debug!("Received watch event: {:?}", event); + match event { + // Create events + WatchEvent::Create { name, base_path } => { + if base_path == INPUT_PATH && name.starts_with("event") { + let result = cmd_tx.send(Command::EventDeviceAdded { name }); + if let Err(e) = result { + log::error!("Unable to send command: {:?}", e); + } + } else if name.starts_with("hidraw") { + let result = cmd_tx.send(Command::HIDRawAdded { name }); + if let Err(e) = result { + log::error!("Unable to send command: {:?}", e); + } + } else if base_path == IIO_PATH { + let result = cmd_tx.send(Command::IIODeviceAdded { name }); + if let Err(e) = result { + log::error!("Unable to send command: {:?}", e); + } + } + } + // Delete events + WatchEvent::Delete { name, base_path } => { + if base_path == INPUT_PATH && name.starts_with("event") { + let result = cmd_tx.send(Command::EventDeviceRemoved { name }); + if let Err(e) = result { + log::error!("Unable to send command: {:?}", e); + } + } else if name.starts_with("hidraw") { + let result = cmd_tx.send(Command::HIDRawRemoved { name }); + if let Err(e) = result { + log::error!("Unable to send command: {:?}", e); + } + } else if base_path == IIO_PATH { + let result = cmd_tx.send(Command::IIODeviceRemoved { name }); + if let Err(e) = result { + log::error!("Unable to send command: {:?}", e); + } + } + } + _ => {} + } + } + }); + + Ok(()) + } + + async fn discover_human_interface_devices( + watcher_tx: &mpsc::Sender, + ) -> Result<(), Box> { // Start watcher thread to listen for hidraw device changes if std::path::Path::new(DEV_PATH).exists() { let tx = watcher_tx.clone(); tokio::task::spawn_blocking(move || { - log::debug!("Started watcher thread"); + log::info!("Started hidraw device discovery thread"); watcher::watch(DEV_PATH.into(), tx) }); - log::debug!("Performing initial input device discovery"); // Perform an initial hidraw device discovery let paths = std::fs::read_dir(DEV_PATH)?; for entry in paths { @@ -1111,7 +1174,7 @@ impl Manager { } log::debug!("Discovered hidraw device: {:?}", path); let result = watcher_tx - .send(watcher::WatchEvent::Create { + .send(WatchEvent::Create { name: path, base_path: DEV_PATH.into(), }) @@ -1122,11 +1185,17 @@ impl Manager { } } + Ok(()) + } + + async fn discover_event_devices( + watcher_tx: &mpsc::Sender, + ) -> Result<(), Box> { // Start watcher thread to listen for event device changes if std::path::Path::new(INPUT_PATH).exists() { let tx = watcher_tx.clone(); tokio::task::spawn_blocking(move || { - log::debug!("Started watcher thread"); + log::info!("Started evdev discovery thread"); watcher::watch(INPUT_PATH.into(), tx) }); // Perform an initial event device discovery @@ -1146,7 +1215,7 @@ impl Manager { } log::debug!("Discovered event device: {:?}", path); let result = watcher_tx - .send(watcher::WatchEvent::Create { + .send(WatchEvent::Create { name: path, base_path: INPUT_PATH.into(), }) @@ -1156,91 +1225,57 @@ impl Manager { } } } + Ok(()) + } + async fn discover_iio_devices( + watcher_tx: &mpsc::Sender, + ) -> Result<(), Box> { // Start watcher thread to listen for iio device changes if std::path::Path::new(IIO_PATH).exists() { let tx = watcher_tx.clone(); - tokio::task::spawn_blocking(move || { - log::debug!("Started watcher thread"); - watcher::watch(IIO_PATH.into(), tx) - }); - - // Perform an initial iio device discovery - let paths = std::fs::read_dir(IIO_PATH)?; - for entry in paths { - if let Err(e) = entry { - log::warn!("Unable to read from directory: {:?}", e); - continue; - } - let path = entry.unwrap().file_name(); - let path = path.into_string().ok(); - let Some(path) = path else { - continue; - }; - log::debug!("Discovered iio device: {:?}", path); - let result = watcher_tx - .send(watcher::WatchEvent::Create { - name: path, - base_path: IIO_PATH.into(), - }) - .await; - if let Err(e) = result { - log::error!("Unable to send command: {:?}", e); - } - } - } - log::debug!("Initial input device discovery complete"); - - // Start a task to dispatch filesystem watch events to the `run()` loop - let cmd_tx = self.tx.clone(); - tokio::spawn(async move { - log::debug!("Dispatching filesystem watch events"); - while let Some(event) = watcher_rx.recv().await { - log::debug!("Received watch event: {:?}", event); - match event { - // Create events - watcher::WatchEvent::Create { name, base_path } => { - if base_path == INPUT_PATH && name.starts_with("event") { - let result = cmd_tx.send(Command::EventDeviceAdded { name }); - if let Err(e) = result { - log::error!("Unable to send command: {:?}", e); - } - } else if name.starts_with("hidraw") { - let result = cmd_tx.send(Command::HIDRawAdded { name }); - if let Err(e) = result { - log::error!("Unable to send command: {:?}", e); - } - } else if base_path == IIO_PATH { - let result = cmd_tx.send(Command::IIODeviceAdded { name }); - if let Err(e) = result { - log::error!("Unable to send command: {:?}", e); - } + tokio::task::spawn(async move { + log::info!("Started iio device discovery loop."); + // Apply some duct tape here... + // Perform iio device discovery + let mut discovered_paths: Vec = Vec::new(); + loop { + let paths = match std::fs::read_dir(IIO_PATH) { + Ok(paths) => paths, + Err(e) => { + log::error!("Got error reading path. {e:?}"); + return; } - } - // Delete events - watcher::WatchEvent::Delete { name, base_path } => { - if base_path == INPUT_PATH && name.starts_with("event") { - let result = cmd_tx.send(Command::EventDeviceRemoved { name }); - if let Err(e) = result { - log::error!("Unable to send command: {:?}", e); - } - } else if name.starts_with("hidraw") { - let result = cmd_tx.send(Command::HIDRawRemoved { name }); - if let Err(e) = result { - log::error!("Unable to send command: {:?}", e); - } - } else if base_path == IIO_PATH { - let result = cmd_tx.send(Command::IIODeviceRemoved { name }); + }; + for entry in paths { + if let Err(e) = entry { + log::warn!("Unable to read from directory: {:?}", e); + continue; + } + log::debug!("Found path: {entry:?}"); + let path = entry.unwrap().file_name(); + let path = path.into_string().ok(); + let Some(path) = path else { + continue; + }; + log::debug!("Discovered iio device: {:?}", path); + if !discovered_paths.contains(&path) { + let result = tx + .send(WatchEvent::Create { + name: path.clone(), + base_path: IIO_PATH.into(), + }) + .await; if let Err(e) = result { log::error!("Unable to send command: {:?}", e); } + discovered_paths.push(path) } } - _ => {} + tokio::time::sleep(Duration::from_secs(1)).await; } - } - }); - + }); + } Ok(()) }