buttplug/server/device/protocol/
xuanhuan.rs1use crate::{
9 core::{errors::ButtplugDeviceError, message::Endpoint},
10 server::device::{
11 configuration::{ProtocolCommunicationSpecifier, UserDeviceDefinition, UserDeviceIdentifier},
12 hardware::{Hardware, HardwareCommand, HardwareWriteCmd},
13 protocol::{
14 generic_protocol_initializer_setup,
15 ProtocolHandler,
16 ProtocolIdentifier,
17 ProtocolInitializer,
18 },
19 },
20 util::{async_manager, sleep},
21};
22use async_trait::async_trait;
23use std::{sync::Arc, time::Duration};
24use tokio::sync::RwLock;
25
26generic_protocol_initializer_setup!(Xuanhuan, "xuanhuan");
27
28#[derive(Default)]
29pub struct XuanhuanInitializer {}
30
31#[async_trait]
32impl ProtocolInitializer for XuanhuanInitializer {
33 async fn initialize(
34 &mut self,
35 hardware: Arc<Hardware>,
36 _: &UserDeviceDefinition,
37 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> {
38 Ok(Arc::new(Xuanhuan::new(hardware)))
39 }
40}
41
42async fn vibration_update_handler(device: Arc<Hardware>, command_holder: Arc<RwLock<Vec<u8>>>) {
43 info!("Entering Xuanhuan Control Loop");
44 let mut current_command = command_holder.read().await.clone();
45 while current_command == vec![0x03, 0x02, 0x00, 0x00]
46 || device
47 .write_value(&HardwareWriteCmd::new(Endpoint::Tx, current_command, true))
48 .await
49 .is_ok()
50 {
51 sleep(Duration::from_millis(300)).await;
52 current_command = command_holder.read().await.clone();
53 }
54 info!("Xuanhuan control loop exiting, most likely due to device disconnection.");
55}
56
57pub struct Xuanhuan {
58 current_command: Arc<RwLock<Vec<u8>>>,
59}
60
61impl Xuanhuan {
62 fn new(device: Arc<Hardware>) -> Self {
63 let current_command = Arc::new(RwLock::new(vec![0x03, 0x02, 0x00, 0x00]));
64 let current_command_clone = current_command.clone();
65 async_manager::spawn(
66 async move { vibration_update_handler(device, current_command_clone).await },
67 );
68 Self { current_command }
69 }
70}
71
72impl ProtocolHandler for Xuanhuan {
73 fn handle_scalar_vibrate_cmd(
74 &self,
75 _index: u32,
76 scalar: u32,
77 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
78 let current_command = self.current_command.clone();
79 async_manager::spawn(async move {
80 let write_mutex = current_command.clone();
81 let mut command_writer = write_mutex.write().await;
82 *command_writer = vec![0x03, 0x02, 0x00, scalar as u8];
83 });
84 Ok(vec![HardwareWriteCmd::new(
85 Endpoint::Tx,
86 vec![0x03, 0x02, 0x00, scalar as u8],
87 true,
88 )
89 .into()])
90 }
91}