Buttplug sex toy control library
1use super::hidapi_async::HidAsyncDevice;
2use async_trait::async_trait;
3use buttplug_core::errors::ButtplugDeviceError;
4use buttplug_server::device::hardware::{
5 GenericHardwareSpecializer,
6 Hardware,
7 HardwareConnector,
8 HardwareEvent,
9 HardwareInternal,
10 HardwareReadCmd,
11 HardwareReading,
12 HardwareSpecializer,
13 HardwareSubscribeCmd,
14 HardwareUnsubscribeCmd,
15 HardwareWriteCmd,
16};
17use buttplug_server_device_config::{Endpoint, ProtocolCommunicationSpecifier, VIDPIDSpecifier};
18use futures::{AsyncWriteExt, future::BoxFuture};
19use hidapi::{DeviceInfo, HidApi};
20use std::{
21 fmt::{self, Debug},
22 sync::{
23 Arc,
24 atomic::{AtomicBool, Ordering},
25 },
26};
27use tokio::sync::{Mutex, broadcast};
28
29pub struct HidHardwareConnector {
30 hid_instance: Arc<HidApi>,
31 device_info: DeviceInfo,
32}
33
34impl HidHardwareConnector {
35 pub fn new(hid_instance: Arc<HidApi>, device_info: &DeviceInfo) -> Self {
36 Self {
37 hid_instance,
38 device_info: device_info.clone(),
39 }
40 }
41}
42
43impl Debug for HidHardwareConnector {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 f.debug_struct("HIDHardwareConnector")
46 .field("vid", &self.device_info.vendor_id())
47 .field("pid", &self.device_info.product_id())
48 .finish()
49 }
50}
51
52#[async_trait]
53impl HardwareConnector for HidHardwareConnector {
54 fn specifier(&self) -> ProtocolCommunicationSpecifier {
55 info!(
56 "Specifier for {}: {:#04x} {:#04x}",
57 self.device_info.product_string().unwrap(),
58 self.device_info.vendor_id(),
59 self.device_info.product_id()
60 );
61 ProtocolCommunicationSpecifier::HID(VIDPIDSpecifier::new(
62 self.device_info.vendor_id(),
63 self.device_info.product_id(),
64 ))
65 }
66
67 async fn connect(&mut self) -> Result<Box<dyn HardwareSpecializer>, ButtplugDeviceError> {
68 let device = self.device_info.open_device(&self.hid_instance).unwrap();
69 let device_impl_internal = HIDDeviceImpl::new(HidAsyncDevice::new(device).unwrap());
70 info!(
71 "New HID device created: {}",
72 self.device_info.product_string().unwrap()
73 );
74 let hardware = Hardware::new(
75 self.device_info.product_string().unwrap(),
76 self.device_info.serial_number().unwrap(),
77 &[Endpoint::Rx, Endpoint::Tx],
78 &None,
79 false,
80 Box::new(device_impl_internal),
81 );
82 Ok(Box::new(GenericHardwareSpecializer::new(hardware)))
83 }
84}
85
86pub struct HIDDeviceImpl {
87 connected: Arc<AtomicBool>,
88 device_event_sender: broadcast::Sender<HardwareEvent>,
89 device: Arc<Mutex<HidAsyncDevice>>,
90}
91
92impl HIDDeviceImpl {
93 pub fn new(device: HidAsyncDevice) -> Self {
94 let (device_event_sender, _) = broadcast::channel(256);
95 Self {
96 device: Arc::new(Mutex::new(device)),
97 connected: Arc::new(AtomicBool::new(true)),
98 device_event_sender,
99 }
100 }
101}
102
103impl HardwareInternal for HIDDeviceImpl {
104 fn event_stream(&self) -> broadcast::Receiver<HardwareEvent> {
105 self.device_event_sender.subscribe()
106 }
107
108 fn disconnect(&self) -> BoxFuture<'static, Result<(), ButtplugDeviceError>> {
109 let connected = self.connected.clone();
110 Box::pin(async move {
111 connected.store(false, Ordering::Relaxed);
112 Ok(())
113 })
114 }
115
116 fn read_value(
117 &self,
118 _msg: &HardwareReadCmd,
119 ) -> BoxFuture<'static, Result<HardwareReading, ButtplugDeviceError>> {
120 unimplemented!();
121 }
122
123 fn write_value(
124 &self,
125 msg: &HardwareWriteCmd,
126 ) -> BoxFuture<'static, Result<(), ButtplugDeviceError>> {
127 let device = self.device.clone();
128 let data = msg.data().clone();
129 Box::pin(async move {
130 device.lock().await.write(&data).await.map_err(|e| {
131 ButtplugDeviceError::DeviceCommunicationError(format!("Cannot write to HID Device: {e:?}."))
132 })?;
133 Ok(())
134 })
135 }
136
137 fn subscribe(
138 &self,
139 _msg: &HardwareSubscribeCmd,
140 ) -> BoxFuture<'static, Result<(), ButtplugDeviceError>> {
141 unimplemented!();
142 }
143
144 fn unsubscribe(
145 &self,
146 _msg: &HardwareUnsubscribeCmd,
147 ) -> BoxFuture<'static, Result<(), ButtplugDeviceError>> {
148 unimplemented!();
149 }
150}