buttplug/server/device/protocol/
xuanhuan.rs

1// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2//
3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved.
4//
5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6// for full license information.
7
8use 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}