Buttplug sex toy control library
at dev 3.6 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 buttplug_core::errors::ButtplugDeviceError; 9use buttplug_core::message::OutputType; 10use buttplug_server_device_config::Endpoint; 11use buttplug_server_device_config::{ 12 ProtocolCommunicationSpecifier, 13 ServerDeviceDefinition, 14 UserDeviceIdentifier, 15}; 16 17use crate::device::{ 18 hardware::{Hardware, HardwareCommand, HardwareReadCmd, HardwareWriteCmd}, 19 protocol::{ProtocolHandler, ProtocolIdentifier, ProtocolInitializer}, 20}; 21use async_trait::async_trait; 22use std::sync::Arc; 23use std::sync::atomic::{AtomicU8, Ordering}; 24use uuid::{Uuid, uuid}; 25 26const VIBRATISSIMO_PROTOCOL_UUID: Uuid = uuid!("66ef7aa4-1e6a-4067-9066-dcb53c7647f2"); 27 28pub mod setup { 29 use crate::device::protocol::{ProtocolIdentifier, ProtocolIdentifierFactory}; 30 #[derive(Default)] 31 pub struct VibratissimoIdentifierFactory {} 32 33 impl ProtocolIdentifierFactory for VibratissimoIdentifierFactory { 34 fn identifier(&self) -> &str { 35 "vibratissimo" 36 } 37 38 fn create(&self) -> Box<dyn ProtocolIdentifier> { 39 Box::new(super::VibratissimoIdentifier::default()) 40 } 41 } 42} 43 44#[derive(Default)] 45pub struct VibratissimoIdentifier {} 46 47#[async_trait] 48impl ProtocolIdentifier for VibratissimoIdentifier { 49 async fn identify( 50 &mut self, 51 hardware: Arc<Hardware>, 52 _: ProtocolCommunicationSpecifier, 53 ) -> Result<(UserDeviceIdentifier, Box<dyn ProtocolInitializer>), ButtplugDeviceError> { 54 let result = hardware 55 .read_value(&HardwareReadCmd::new( 56 VIBRATISSIMO_PROTOCOL_UUID, 57 Endpoint::RxBLEModel, 58 128, 59 500, 60 )) 61 .await?; 62 let ident = 63 String::from_utf8(result.data().to_vec()).unwrap_or_else(|_| hardware.name().to_owned()); 64 Ok(( 65 UserDeviceIdentifier::new(hardware.address(), "vibratissimo", &Some(ident)), 66 Box::new(VibratissimoInitializer::default()), 67 )) 68 } 69} 70 71#[derive(Default)] 72pub struct VibratissimoInitializer {} 73 74#[async_trait] 75impl ProtocolInitializer for VibratissimoInitializer { 76 async fn initialize( 77 &mut self, 78 _: Arc<Hardware>, 79 def: &ServerDeviceDefinition, 80 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 81 let num_vibrators: u8 = def 82 .features() 83 .iter() 84 .filter(|x| { 85 x.output() 86 .as_ref() 87 .is_some_and(|x| x.contains(OutputType::Vibrate)) 88 }) 89 .count() as u8; 90 Ok(Arc::new(Vibratissimo::new(num_vibrators))) 91 } 92} 93 94pub struct Vibratissimo { 95 speeds: Vec<AtomicU8>, 96} 97 98impl Vibratissimo { 99 fn new(num_vibrators: u8) -> Self { 100 let speeds: Vec<AtomicU8> = std::iter::repeat_with(AtomicU8::default) 101 .take(num_vibrators as usize) 102 .collect(); 103 Self { speeds } 104 } 105} 106 107impl ProtocolHandler for Vibratissimo { 108 fn handle_output_vibrate_cmd( 109 &self, 110 feature_index: u32, 111 feature_id: Uuid, 112 speed: u32, 113 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 114 self.speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed); 115 let mut data = vec![]; 116 for cmd in &self.speeds { 117 data.push(cmd.load(std::sync::atomic::Ordering::Relaxed)); 118 } 119 if data.len() == 1 { 120 data.push(0x00); 121 } 122 123 // Put the device in write mode 124 Ok(vec![ 125 HardwareWriteCmd::new(&[feature_id], Endpoint::TxMode, vec![0x03, 0xff], false).into(), 126 HardwareWriteCmd::new(&[feature_id], Endpoint::TxVibrate, data, false).into(), 127 ]) 128 } 129}