Buttplug sex toy control library
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 37// Time between Hgod update commands, in milliseconds. 38const HGOD_COMMAND_DELAY_MS: u64 = 100; 39 40const HGOD_PROTOCOL_UUID: Uuid = uuid!("0a086d5b-9918-4b73-b2dd-86ed66de6f51"); 41generic_protocol_initializer_setup!(Hgod, "hgod"); 42 43#[derive(Default)] 44pub struct HgodInitializer {} 45 46#[async_trait] 47impl ProtocolInitializer for HgodInitializer { 48 async fn initialize( 49 &mut self, 50 hardware: Arc<Hardware>, 51 _: &ServerDeviceDefinition, 52 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 53 Ok(Arc::new(Hgod::new(hardware))) 54 } 55} 56 57pub struct Hgod { 58 last_command: Arc<AtomicU8>, 59} 60 61impl Hgod { 62 fn new(hardware: Arc<Hardware>) -> Self { 63 let last_command = Arc::new(AtomicU8::new(0)); 64 65 let last_command_clone = last_command.clone(); 66 async_manager::spawn(async move { 67 send_hgod_updates(hardware, last_command_clone).await; 68 }); 69 70 Self { last_command } 71 } 72} 73 74// HGod toys vibes only last ~100ms seconds. 75async fn send_hgod_updates(device: Arc<Hardware>, data: Arc<AtomicU8>) { 76 loop { 77 let speed = data.load(Ordering::Relaxed); 78 let command = vec![0x55, 0x04, 0, 0, 0, speed]; 79 if speed > 0 80 && let Err(e) = device 81 .write_value(&HardwareWriteCmd::new( 82 &[HGOD_PROTOCOL_UUID], 83 Endpoint::Tx, 84 command, 85 false, 86 )) 87 .await 88 { 89 error!( 90 "Got an error from a hgod device, exiting control loop: {:?}", 91 e 92 ); 93 break; 94 } 95 sleep(Duration::from_millis(HGOD_COMMAND_DELAY_MS)).await; 96 } 97} 98 99impl ProtocolHandler for Hgod { 100 fn handle_output_vibrate_cmd( 101 &self, 102 _feature_index: u32, 103 _feature_id: Uuid, 104 speed: u32, 105 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 106 self.last_command.store(speed as u8, Ordering::Relaxed); 107 Ok(vec![]) 108 } 109}