Buttplug sex toy control library
at dev 2.8 kB view raw
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::device::{ 9 hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, 10 protocol::{ 11 ProtocolHandler, 12 ProtocolIdentifier, 13 ProtocolInitializer, 14 generic_protocol_initializer_setup, 15 }, 16}; 17use async_trait::async_trait; 18use buttplug_core::{ 19 errors::ButtplugDeviceError, 20 util::{async_manager, sleep}, 21}; 22use buttplug_server_device_config::{ 23 Endpoint, 24 ProtocolCommunicationSpecifier, 25 ServerDeviceDefinition, 26 UserDeviceIdentifier, 27}; 28use std::{ 29 sync::{ 30 Arc, 31 atomic::{AtomicU8, Ordering}, 32 }, 33 time::Duration, 34}; 35use uuid::{Uuid, uuid}; 36 37const XUANHUAN_PROTOCOL_ID: Uuid = uuid!("e9f9f8ab-4fd5-4573-a4ec-ab542568849b"); 38generic_protocol_initializer_setup!(Xuanhuan, "xuanhuan"); 39 40#[derive(Default)] 41pub struct XuanhuanInitializer {} 42 43#[async_trait] 44impl ProtocolInitializer for XuanhuanInitializer { 45 async fn initialize( 46 &mut self, 47 hardware: Arc<Hardware>, 48 _: &ServerDeviceDefinition, 49 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 50 Ok(Arc::new(Xuanhuan::new(hardware))) 51 } 52} 53 54async fn vibration_update_handler(device: Arc<Hardware>, command_holder: Arc<AtomicU8>) { 55 info!("Entering Xuanhuan Control Loop"); 56 loop { 57 let speed = command_holder.load(Ordering::Relaxed); 58 if speed != 0 { 59 let current_command = vec![0x03, 0x02, 0x00, speed]; 60 if device 61 .write_value(&HardwareWriteCmd::new( 62 &[XUANHUAN_PROTOCOL_ID], 63 Endpoint::Tx, 64 current_command, 65 true, 66 )) 67 .await 68 .is_err() 69 { 70 break; 71 } 72 } 73 sleep(Duration::from_millis(300)).await; 74 } 75 info!("Xuanhuan control loop exiting, most likely due to device disconnection."); 76} 77 78pub struct Xuanhuan { 79 current_command: Arc<AtomicU8>, 80} 81 82impl Xuanhuan { 83 fn new(device: Arc<Hardware>) -> Self { 84 let current_command = Arc::new(AtomicU8::new(0)); 85 let current_command_clone = current_command.clone(); 86 async_manager::spawn( 87 async move { vibration_update_handler(device, current_command_clone).await }, 88 ); 89 Self { current_command } 90 } 91} 92 93impl ProtocolHandler for Xuanhuan { 94 fn handle_output_vibrate_cmd( 95 &self, 96 _feature_index: u32, 97 _feature_id: Uuid, 98 speed: u32, 99 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 100 let speed = speed as u8; 101 self.current_command.store(speed, Ordering::Relaxed); 102 103 Ok(vec![ 104 HardwareWriteCmd::new( 105 &[XUANHUAN_PROTOCOL_ID], 106 Endpoint::Tx, 107 vec![0x03, 0x02, 0x00, speed], 108 true, 109 ) 110 .into(), 111 ]) 112 } 113}