diff --git a/src/dbus/interface/source/iio_imu.rs b/src/dbus/interface/source/iio_imu.rs index 375dde42..5773b679 100644 --- a/src/dbus/interface/source/iio_imu.rs +++ b/src/dbus/interface/source/iio_imu.rs @@ -1,21 +1,23 @@ use std::error::Error; -use crate::iio::device::Device; -use tokio::sync::mpsc::Sender; +use crate::{iio::device::Device, input::source::client::SourceDeviceClient}; use zbus::{fdo, Connection}; use zbus_macros::interface; -use crate::input::source::{iio::get_dbus_path, SourceCommand}; +use crate::input::source::iio::get_dbus_path; /// DBusInterface exposing information about a HIDRaw device pub struct SourceIioImuInterface { - info: Device, - tx: Sender, + _info: Device, + source_device: SourceDeviceClient, } impl SourceIioImuInterface { - pub fn new(info: Device, tx: Sender) -> SourceIioImuInterface { - SourceIioImuInterface { info, tx } + pub fn new(info: Device, source_device: SourceDeviceClient) -> SourceIioImuInterface { + SourceIioImuInterface { + _info: info, + source_device, + } } /// Creates a new instance of the source hidraw interface on DBus. Returns @@ -23,14 +25,14 @@ impl SourceIioImuInterface { pub async fn listen_on_dbus( conn: Connection, info: Device, - tx: Sender, + source_device: SourceDeviceClient, ) -> Result<(), Box> { let Some(id) = info.id.clone() else { return Err("Failed to get ID of IIO device".into()); }; let path = get_dbus_path(id); - let iface = SourceIioImuInterface::new(info, tx); + let iface = SourceIioImuInterface::new(info, source_device); tokio::task::spawn(async move { log::debug!("Starting dbus interface: {path}"); let result = conn.object_server().at(path.clone(), iface).await; @@ -48,20 +50,7 @@ impl SourceIioImuInterface { impl SourceIioImuInterface { #[zbus(property)] async fn accel_sample_rate(&self) -> fdo::Result { - let (tx, rx) = std::sync::mpsc::channel(); - if let Err(e) = self - .tx - .send(SourceCommand::GetSampleRate("accel".to_string(), tx)) - .await - { - return Err(fdo::Error::Failed(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(fdo::Error::Failed( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.get_sample_rate("accel").await { Ok(result) => Ok(result), Err(e) => Err(fdo::Error::Failed(e.to_string())), } @@ -69,20 +58,7 @@ impl SourceIioImuInterface { #[zbus(property)] async fn accel_sample_rates_avail(&self) -> fdo::Result> { - let (tx, rx) = std::sync::mpsc::channel(); - if let Err(e) = self - .tx - .send(SourceCommand::GetSampleRatesAvail("accel".to_string(), tx)) - .await - { - return Err(fdo::Error::Failed(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(fdo::Error::Failed( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.get_sample_rates_avail("accel").await { Ok(result) => Ok(result), Err(e) => Err(fdo::Error::Failed(e.to_string())), } @@ -90,20 +66,7 @@ impl SourceIioImuInterface { #[zbus(property)] async fn angvel_sample_rate(&self) -> fdo::Result { - let (tx, rx) = std::sync::mpsc::channel(); - if let Err(e) = self - .tx - .send(SourceCommand::GetSampleRate("gyro".to_string(), tx)) - .await - { - return Err(fdo::Error::Failed(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(fdo::Error::Failed( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.get_sample_rate("gyro").await { Ok(result) => Ok(result), Err(e) => Err(fdo::Error::Failed(e.to_string())), } @@ -111,20 +74,7 @@ impl SourceIioImuInterface { #[zbus(property)] async fn angvel_sample_rates_avail(&self) -> fdo::Result> { - let (tx, rx) = std::sync::mpsc::channel(); - if let Err(e) = self - .tx - .send(SourceCommand::GetSampleRatesAvail("gyro".to_string(), tx)) - .await - { - return Err(fdo::Error::Failed(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(fdo::Error::Failed( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.get_sample_rates_avail("gyro").await { Ok(result) => Ok(result), Err(e) => Err(fdo::Error::Failed(e.to_string())), } @@ -132,25 +82,11 @@ impl SourceIioImuInterface { #[zbus(property)] async fn set_accel_sample_rate(&self, sample_rate: f64) -> zbus::Result<()> { - let (tx, rx) = std::sync::mpsc::channel(); - - if let Err(e) = self - .tx - .send(SourceCommand::SetSampleRate( - "accel".to_string(), - sample_rate, - tx, - )) + match self + .source_device + .set_sample_rate("accel", sample_rate) .await { - return Err(zbus::Error::Failure(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(zbus::Error::Failure( - "Channel closed with no response.".to_string(), - )); - }; - match response { Ok(result) => Ok(result), Err(e) => Err(zbus::Error::Failure(e.to_string())), } @@ -158,25 +94,11 @@ impl SourceIioImuInterface { #[zbus(property)] async fn set_angvel_sample_rate(&self, sample_rate: f64) -> zbus::Result<()> { - let (tx, rx) = std::sync::mpsc::channel(); - - if let Err(e) = self - .tx - .send(SourceCommand::SetSampleRate( - "gyro".to_string(), - sample_rate, - tx, - )) + match self + .source_device + .set_sample_rate("gyro", sample_rate) .await { - return Err(zbus::Error::Failure(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(zbus::Error::Failure( - "Channel closed with no response.".to_string(), - )); - }; - match response { Ok(result) => Ok(result), Err(e) => Err(zbus::Error::Failure(e.to_string())), } @@ -184,20 +106,7 @@ impl SourceIioImuInterface { // #[zbus(property)] async fn accel_scale(&self) -> fdo::Result { - let (tx, rx) = std::sync::mpsc::channel(); - if let Err(e) = self - .tx - .send(SourceCommand::GetScale("accel".to_string(), tx)) - .await - { - return Err(fdo::Error::Failed(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(fdo::Error::Failed( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.get_scale("accel").await { Ok(result) => Ok(result), Err(e) => Err(fdo::Error::Failed(e.to_string())), } @@ -205,20 +114,7 @@ impl SourceIioImuInterface { #[zbus(property)] async fn accel_scales_avail(&self) -> fdo::Result> { - let (tx, rx) = std::sync::mpsc::channel(); - if let Err(e) = self - .tx - .send(SourceCommand::GetScalesAvail("accel".to_string(), tx)) - .await - { - return Err(fdo::Error::Failed(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(fdo::Error::Failed( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.get_scales_available("accel").await { Ok(result) => Ok(result), Err(e) => Err(fdo::Error::Failed(e.to_string())), } @@ -226,20 +122,7 @@ impl SourceIioImuInterface { #[zbus(property)] async fn angvel_scale(&self) -> fdo::Result { - let (tx, rx) = std::sync::mpsc::channel(); - if let Err(e) = self - .tx - .send(SourceCommand::GetScale("gyro".to_string(), tx)) - .await - { - return Err(fdo::Error::Failed(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(fdo::Error::Failed( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.get_scale("gyro").await { Ok(result) => Ok(result), Err(e) => Err(fdo::Error::Failed(e.to_string())), } @@ -247,20 +130,7 @@ impl SourceIioImuInterface { #[zbus(property)] async fn angvel_scales_avail(&self) -> fdo::Result> { - let (tx, rx) = std::sync::mpsc::channel(); - if let Err(e) = self - .tx - .send(SourceCommand::GetScalesAvail("gyro".to_string(), tx)) - .await - { - return Err(fdo::Error::Failed(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(fdo::Error::Failed( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.get_scales_available("gyro").await { Ok(result) => Ok(result), Err(e) => Err(fdo::Error::Failed(e.to_string())), } @@ -268,21 +138,7 @@ impl SourceIioImuInterface { #[zbus(property)] async fn set_accel_scale(&self, scale: f64) -> zbus::Result<()> { - let (tx, rx) = std::sync::mpsc::channel(); - - if let Err(e) = self - .tx - .send(SourceCommand::SetScale("accel".to_string(), scale, tx)) - .await - { - return Err(zbus::Error::Failure(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(zbus::Error::Failure( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.set_scale("accel", scale).await { Ok(result) => Ok(result), Err(e) => Err(zbus::Error::Failure(e.to_string())), } @@ -290,21 +146,7 @@ impl SourceIioImuInterface { #[zbus(property)] async fn set_angvel_scale(&self, scale: f64) -> zbus::Result<()> { - let (tx, rx) = std::sync::mpsc::channel(); - - if let Err(e) = self - .tx - .send(SourceCommand::SetScale("gyro".to_string(), scale, tx)) - .await - { - return Err(zbus::Error::Failure(e.to_string())); - } - let Ok(response) = rx.recv() else { - return Err(zbus::Error::Failure( - "Channel closed with no response.".to_string(), - )); - }; - match response { + match self.source_device.set_scale("gyro", scale).await { Ok(result) => Ok(result), Err(e) => Err(zbus::Error::Failure(e.to_string())), } diff --git a/src/input/composite_device/mod.rs b/src/input/composite_device/mod.rs index 7712f256..97feaf2a 100644 --- a/src/input/composite_device/mod.rs +++ b/src/input/composite_device/mod.rs @@ -39,7 +39,9 @@ use crate::{ use self::{client::CompositeDeviceClient, command::CompositeCommand}; -use super::{manager::ManagerCommand, output_event::OutputEvent, source::SourceCommand}; +use super::{ + manager::ManagerCommand, output_event::OutputEvent, source::client::SourceDeviceClient, +}; /// Size of the command channel buffer for processing input events and commands. const BUFFER_SIZE: usize = 16384; @@ -102,7 +104,7 @@ pub struct CompositeDevice { rx: mpsc::Receiver, /// Map of source device id to their respective transmitter channel. /// E.g. {"evdev://event0": } - source_devices: HashMap>, + source_devices: HashMap, /// Source devices that this composite device will consume. source_devices_discovered: Vec, /// HashSet of source devices that are blocked from passing their input events to target @@ -490,7 +492,7 @@ impl CompositeDevice { // Send stop command to all source devices for (path, source) in &self.source_devices { - if let Err(e) = source.send(SourceCommand::Stop).await { + if let Err(e) = source.stop().await { log::debug!("Failed to stop source device {path}: {e:?}"); } } @@ -559,17 +561,17 @@ impl CompositeDevice { continue; } - let source_tx = source_device.transmitter(); + let source_tx = source_device.client(); self.source_devices.insert(device_id.clone(), source_tx); let tx = self.tx.clone(); // Add the IIO IMU Dbus interface. We do this here because it needs the source // device transmitter and this is the only place we can refrence it at the moment. - if let SourceDevice::IIODevice(ref device) = source_device { + if let SourceDevice::Iio(ref device) = source_device { SourceIioImuInterface::listen_on_dbus( self.conn.clone(), device.get_info(), - device.transmitter(), + device.client(), ) .await?; } @@ -657,9 +659,7 @@ impl CompositeDevice { continue; }; log::debug!("Updating effect {source_effect_id} from {source_id}"); - source - .send(SourceCommand::UpdateEffect(*source_effect_id, *data)) - .await?; + source.update_effect(*source_effect_id, *data).await?; } target_dev.send(Some(*id))?; return Ok(()); @@ -669,31 +669,13 @@ impl CompositeDevice { let mut source_effect_ids = HashMap::new(); for (source_id, source) in self.source_devices.iter() { log::debug!("Uploading effect to {source_id}"); - let (tx, rx) = std::sync::mpsc::channel(); - match source.try_send(SourceCommand::UploadEffect(*data, tx)) { - Ok(_) => {} - Err(e) => log::error!("Error sending UploadEffect: {:?}", e), - }; - - // Wait for the result of the upload - match rx.recv_timeout(Duration::from_secs(1)) { - Ok(upload_result) => { - if let Err(e) = upload_result { - log::debug!( - "Failed to upload FF effect to {source_id}: {:?}", - e - ); - continue; - } - let source_effect_id = upload_result.unwrap(); + match source.upload_effect(*data).await { + Ok(source_effect_id) => { log::debug!("Successfully uploaded effect with source effect id {source_effect_id}"); source_effect_ids.insert(source_id.clone(), source_effect_id); } - Err(err) => { - log::error!( - "Failed to receive response from source device {source_id} to upload effect: {:?}", - err - ); + Err(e) => { + log::error!("Error uploading effect: {:?}", e); } } } @@ -725,25 +707,8 @@ impl CompositeDevice { continue; }; log::debug!("Erasing effect from {source_id}"); - let (tx, rx) = std::sync::mpsc::channel(); - source - .send(SourceCommand::EraseEffect(*source_effect_id, tx)) - .await?; - - // Wait for the result of the erase - match rx.recv_timeout(Duration::from_secs(1)) { - Ok(erase_result) => { - if let Err(e) = erase_result { - log::debug!( - "Failed to erase FF effect from {source_id}: {:?}", - e - ); - continue; - } - } - Err(err) => { - log::error!("Failed to receive response from source device {source_id} to erase effect: {:?}", err); - } + if let Err(e) = source.erase_effect(*source_effect_id).await { + log::debug!("Failed to erase FF effect from {source_id}: {:?}", e); } } } @@ -791,24 +756,16 @@ impl CompositeDevice { let output_event = OutputEvent::Evdev(new_event); // Write the FF event to the source device - let event = SourceCommand::WriteEvent(output_event); - match source.try_send(event) { - Ok(_) => {} - Err(e) => { - log::error!("Failed to send Output event to {}. {:?}", source_id, e) - } - }; + if let Err(e) = source.write_event(output_event).await { + log::error!("Failed to send Output event to {}. {:?}", source_id, e) + } continue; } } - let event = SourceCommand::WriteEvent(event.clone()); - match source.try_send(event) { - Ok(_) => {} - Err(e) => { - log::error!("Failed to send Output event to {}. {:?}", source_id, e) - } - }; + if let Err(e) = source.write_event(event.clone()).await { + log::error!("Failed to send Output event to {}. {:?}", source_id, e) + } } //log::trace!("Finished processing output events."); @@ -1400,12 +1357,12 @@ impl CompositeDevice { // Create an instance of the device log::debug!("Adding source device: {:?}", info); let device = source::evdev::EventDevice::new(info.clone(), self.client()); - SourceDevice::EventDevice(device) + SourceDevice::Event(device) } SourceDeviceInfo::HIDRawDeviceInfo(info) => { log::debug!("Adding source device: {:?}", info); let device = source::hidraw::HIDRawDevice::new(info, self.client()); - SourceDevice::HIDRawDevice(device) + SourceDevice::HIDRaw(device) } SourceDeviceInfo::IIODeviceInfo(info) => { // Get any defined config for the IIO device @@ -1418,7 +1375,7 @@ impl CompositeDevice { log::debug!("Adding source device: {:?}", info); let device = source::iio::IIODevice::new(info, config, self.client()); - SourceDevice::IIODevice(device) + SourceDevice::Iio(device) } }; diff --git a/src/input/source/client.rs b/src/input/source/client.rs new file mode 100644 index 00000000..d6cfa373 --- /dev/null +++ b/src/input/source/client.rs @@ -0,0 +1,203 @@ +use std::{sync::mpsc::channel, time::Duration}; + +use evdev::FFEffectData; +use thiserror::Error; +use tokio::sync::mpsc::{ + error::{SendError, TrySendError}, + Sender, +}; + +use crate::input::output_event::OutputEvent; + +use super::command::SourceCommand; + +/// Possible errors for a source device client +#[derive(Error, Debug)] +pub enum ClientError { + #[error("failed to send command to device")] + SendError(SendError), + #[error("failed to try to send command to device")] + TrySendError(TrySendError), + #[error("service encountered an error processing the request")] + ServiceError(Box), + #[error("device no longer exists")] + ChannelClosed, +} + +impl From> for ClientError { + fn from(err: SendError) -> Self { + Self::SendError(err) + } +} + +impl From> for ClientError { + fn from(err: TrySendError) -> Self { + Self::TrySendError(err) + } +} + +/// A client for communicating with a source device +#[derive(Debug, Clone)] +pub struct SourceDeviceClient { + tx: Sender, +} + +impl From> for SourceDeviceClient { + fn from(tx: Sender) -> Self { + SourceDeviceClient::new(tx) + } +} + +impl SourceDeviceClient { + pub fn new(tx: Sender) -> Self { + Self { tx } + } + + /// Write the given output event to the source device. Output events are + /// events that flow from an application (like a game) to the physical + /// input device, such as force feedback events. + pub async fn write_event(&self, event: OutputEvent) -> Result<(), ClientError> { + self.tx.send(SourceCommand::WriteEvent(event)).await?; + Ok(()) + } + + /// Upload the given force feedback effect data to the source device. Returns + /// a device-specific id of the uploaded effect if it is successful. + pub async fn upload_effect(&self, effect: FFEffectData) -> Result { + let (tx, rx) = channel(); + self.tx.try_send(SourceCommand::UploadEffect(effect, tx))?; + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(result) => match result { + Ok(id) => Ok(id), + Err(err) => Err(ClientError::ServiceError(err)), + }, + Err(_err) => Err(ClientError::ChannelClosed), + } + } + + /// Update the effect with the given id using the given effect data. + pub async fn update_effect( + &self, + effect_id: i16, + effect: FFEffectData, + ) -> Result<(), ClientError> { + self.tx + .send(SourceCommand::UpdateEffect(effect_id, effect)) + .await?; + Ok(()) + } + + /// Erase the effect with the given id from the source device. + pub async fn erase_effect(&self, effect_id: i16) -> Result<(), ClientError> { + let (tx, rx) = channel(); + self.tx + .try_send(SourceCommand::EraseEffect(effect_id, tx))?; + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(result) => match result { + Ok(_) => Ok(()), + Err(err) => Err(ClientError::ServiceError(err)), + }, + Err(_err) => Err(ClientError::ChannelClosed), + } + } + + /// Get the sample rate of the source device for the given property. This + /// returns how often the device polls for data. Typically used for IIO + /// source devices. + pub async fn get_sample_rate(&self, kind: &str) -> Result { + let (tx, rx) = channel(); + self.tx + .try_send(SourceCommand::GetSampleRate(kind.to_string(), tx))?; + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(result) => match result { + Ok(rate) => Ok(rate), + Err(err) => Err(ClientError::ServiceError(err)), + }, + Err(_err) => Err(ClientError::ChannelClosed), + } + } + + /// Get the sample rates available on the source device for the given property. + /// Typically used for IIO source devices. + pub async fn get_sample_rates_avail(&self, kind: &str) -> Result, ClientError> { + let (tx, rx) = channel(); + self.tx + .try_send(SourceCommand::GetSampleRatesAvail(kind.to_string(), tx))?; + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(result) => match result { + Ok(rates) => Ok(rates), + Err(err) => Err(ClientError::ServiceError(err)), + }, + Err(_err) => Err(ClientError::ChannelClosed), + } + } + + /// Set the sample rate on the source device for the given property. Typically + /// used for IIO source devices. + pub async fn set_sample_rate(&self, kind: &str, rate: f64) -> Result<(), ClientError> { + let (tx, rx) = channel(); + self.tx + .try_send(SourceCommand::SetSampleRate(kind.to_string(), rate, tx))?; + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(result) => match result { + Ok(value) => Ok(value), + Err(err) => Err(ClientError::ServiceError(err)), + }, + Err(_err) => Err(ClientError::ChannelClosed), + } + } + + /// Get the scale of the given property on the source device. The scale is a + /// multiplier used to increase or decrease sensitivity of certain events. + /// Typically used by IIO source devices. + pub async fn get_scale(&self, kind: &str) -> Result { + let (tx, rx) = channel(); + self.tx + .try_send(SourceCommand::GetScale(kind.to_string(), tx))?; + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(result) => match result { + Ok(value) => Ok(value), + Err(err) => Err(ClientError::ServiceError(err)), + }, + Err(_err) => Err(ClientError::ChannelClosed), + } + } + + /// Get the scales available on the source device for the given property. + /// Scale is a multiplier used to increase or decrease sensitivity of certain + /// events. Typically used for IIO source devices. + pub async fn get_scales_available(&self, kind: &str) -> Result, ClientError> { + let (tx, rx) = channel(); + self.tx + .try_send(SourceCommand::GetScalesAvail(kind.to_string(), tx))?; + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(result) => match result { + Ok(value) => Ok(value), + Err(err) => Err(ClientError::ServiceError(err)), + }, + Err(_err) => Err(ClientError::ChannelClosed), + } + } + + /// Set the scale on the source device for the given property. + /// Scale is a multiplier used to increase or decrease sensitivity of certain + /// events. Typically used for IIO source devices. + pub async fn set_scale(&self, kind: &str, scale: f64) -> Result<(), ClientError> { + let (tx, rx) = channel(); + self.tx + .try_send(SourceCommand::SetScale(kind.to_string(), scale, tx))?; + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(result) => match result { + Ok(value) => Ok(value), + Err(err) => Err(ClientError::ServiceError(err)), + }, + Err(_err) => Err(ClientError::ChannelClosed), + } + } + + /// Stop the source device. + pub async fn stop(&self) -> Result<(), ClientError> { + self.tx.send(SourceCommand::Stop).await?; + Ok(()) + } +} diff --git a/src/input/source/command.rs b/src/input/source/command.rs new file mode 100644 index 00000000..002f26e1 --- /dev/null +++ b/src/input/source/command.rs @@ -0,0 +1,39 @@ +use std::{error::Error, sync::mpsc::Sender}; + +use evdev::FFEffectData; + +use crate::input::output_event::OutputEvent; + +/// A [SourceCommand] is a message that can be sent to a [SourceDevice] over +/// a channel. +#[derive(Debug, Clone)] +pub enum SourceCommand { + WriteEvent(OutputEvent), + UploadEffect( + FFEffectData, + Sender>>, + ), + UpdateEffect(i16, FFEffectData), + EraseEffect(i16, Sender>>), + GetSampleRate(String, Sender>>), + GetSampleRatesAvail( + String, + Sender, Box>>, + ), + SetSampleRate( + String, + f64, + Sender>>, + ), + GetScale(String, Sender>>), + GetScalesAvail( + String, + Sender, Box>>, + ), + SetScale( + String, + f64, + Sender>>, + ), + Stop, +} diff --git a/src/input/source/evdev.rs b/src/input/source/evdev.rs index 90d5c997..efb68483 100644 --- a/src/input/source/evdev.rs +++ b/src/input/source/evdev.rs @@ -19,7 +19,7 @@ use crate::{ procfs, }; -use super::SourceCommand; +use super::{client::SourceDeviceClient, SourceCommand}; /// Size of the [SourceCommand] buffer for receiving output events const BUFFER_SIZE: usize = 2048; @@ -51,8 +51,8 @@ impl EventDevice { } /// Returns a transmitter channel that can be used to send events to this device - pub fn transmitter(&self) -> mpsc::Sender { - self.tx.clone() + pub fn client(&self) -> SourceDeviceClient { + self.tx.clone().into() } /// Run the source device handler diff --git a/src/input/source/hidraw.rs b/src/input/source/hidraw.rs index ea6d2148..b3c25a62 100644 --- a/src/input/source/hidraw.rs +++ b/src/input/source/hidraw.rs @@ -14,7 +14,7 @@ use crate::{ input::{capability::Capability, composite_device::client::CompositeDeviceClient}, }; -use super::SourceCommand; +use super::{client::SourceDeviceClient, SourceCommand}; /// Size of the [SourceCommand] buffer for receiving output events const BUFFER_SIZE: usize = 2048; @@ -50,8 +50,8 @@ impl HIDRawDevice { } /// Returns a transmitter channel that can be used to send events to this device - pub fn transmitter(&self) -> mpsc::Sender { - self.tx.clone() + pub fn client(&self) -> SourceDeviceClient { + self.tx.clone().into() } /// Run the source device handler. HIDRaw devices require device-specific diff --git a/src/input/source/iio.rs b/src/input/source/iio.rs index bf98133f..85ecf73e 100644 --- a/src/input/source/iio.rs +++ b/src/input/source/iio.rs @@ -15,7 +15,7 @@ use crate::{ input::{capability::Capability, composite_device::client::CompositeDeviceClient}, }; -use super::SourceCommand; +use super::{client::SourceDeviceClient, SourceCommand}; /// Size of the [SourceCommand] buffer for receiving output events const BUFFER_SIZE: usize = 2048; @@ -93,8 +93,8 @@ impl IIODevice { } /// Returns a transmitter channel that can be used to send events to this device - pub fn transmitter(&self) -> mpsc::Sender { - self.tx.clone() + pub fn client(&self) -> SourceDeviceClient { + self.tx.clone().into() } pub fn get_capabilities(&self) -> Result, Box> { diff --git a/src/input/source/mod.rs b/src/input/source/mod.rs index 98e4f537..cd6da799 100644 --- a/src/input/source/mod.rs +++ b/src/input/source/mod.rs @@ -1,10 +1,11 @@ -use std::{error::Error, sync::mpsc::Sender}; +use std::error::Error; -use ::evdev::FFEffectData; -use tokio::sync::mpsc; +use self::{client::SourceDeviceClient, command::SourceCommand}; -use super::{capability::Capability, output_event::OutputEvent}; +use super::capability::Capability; +pub mod client; +pub mod command; pub mod evdev; pub mod hidraw; pub mod iio; @@ -12,88 +13,54 @@ pub mod iio; /// A [SourceDevice] is any physical input device that emits input events #[derive(Debug)] pub enum SourceDevice { - EventDevice(evdev::EventDevice), - HIDRawDevice(hidraw::HIDRawDevice), - IIODevice(iio::IIODevice), + Event(evdev::EventDevice), + HIDRaw(hidraw::HIDRawDevice), + Iio(iio::IIODevice), } impl SourceDevice { /// Returns a unique identifier for the source device. pub fn get_id(&self) -> String { match self { - SourceDevice::EventDevice(device) => device.get_id(), - SourceDevice::HIDRawDevice(device) => device.get_id(), - SourceDevice::IIODevice(device) => device.get_id(), + SourceDevice::Event(device) => device.get_id(), + SourceDevice::HIDRaw(device) => device.get_id(), + SourceDevice::Iio(device) => device.get_id(), } } - /// Returns a transmitter channel that can be used to send events to this device - pub fn transmitter(&self) -> mpsc::Sender { + /// Returns a client channel that can be used to send events to this device + pub fn client(&self) -> SourceDeviceClient { match self { - SourceDevice::EventDevice(device) => device.transmitter(), - SourceDevice::HIDRawDevice(device) => device.transmitter(), - SourceDevice::IIODevice(device) => device.transmitter(), + SourceDevice::Event(device) => device.client(), + SourceDevice::HIDRaw(device) => device.client(), + SourceDevice::Iio(device) => device.client(), } } /// Run the source device pub async fn run(&mut self) -> Result<(), Box> { match self { - SourceDevice::EventDevice(device) => device.run().await, - SourceDevice::HIDRawDevice(device) => device.run().await, - SourceDevice::IIODevice(device) => device.run().await, + SourceDevice::Event(device) => device.run().await, + SourceDevice::HIDRaw(device) => device.run().await, + SourceDevice::Iio(device) => device.run().await, } } /// Returns the capabilities that this source device can fulfill. pub fn get_capabilities(&self) -> Result, Box> { match self { - SourceDevice::EventDevice(device) => device.get_capabilities(), - SourceDevice::HIDRawDevice(device) => device.get_capabilities(), - SourceDevice::IIODevice(device) => device.get_capabilities(), + SourceDevice::Event(device) => device.get_capabilities(), + SourceDevice::HIDRaw(device) => device.get_capabilities(), + SourceDevice::Iio(device) => device.get_capabilities(), } } /// Returns the full path to the device handler (e.g. /dev/input/event3, /dev/hidraw0) pub fn get_device_path(&self) -> String { match self { - SourceDevice::EventDevice(device) => device.get_device_path(), - SourceDevice::HIDRawDevice(device) => device.get_device_path(), - SourceDevice::IIODevice(device) => device.get_device_path(), + SourceDevice::Event(device) => device.get_device_path(), + SourceDevice::HIDRaw(device) => device.get_device_path(), + SourceDevice::Iio(device) => device.get_device_path(), } } } - -/// A [SourceCommand] is a message that can be sent to a [SourceDevice] over -/// a channel. -#[derive(Debug, Clone)] -pub enum SourceCommand { - WriteEvent(OutputEvent), - UploadEffect( - FFEffectData, - Sender>>, - ), - UpdateEffect(i16, FFEffectData), - EraseEffect(i16, Sender>>), - GetSampleRate(String, Sender>>), - GetSampleRatesAvail( - String, - Sender, Box>>, - ), - SetSampleRate( - String, - f64, - Sender>>, - ), - GetScale(String, Sender>>), - GetScalesAvail( - String, - Sender, Box>>, - ), - SetScale( - String, - f64, - Sender>>, - ), - Stop, -}