Buttplug sex toy control library
at dev 5.8 kB view raw
1// Buttplug Rust Source Code File - See https://buttplug.io for more info. 2// 3// Copyright 2016-2023 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, HardwareReadCmd, HardwareWriteCmd}, 10 protocol::{ProtocolHandler, ProtocolIdentifier, ProtocolInitializer}, 11}; 12use async_trait::async_trait; 13use buttplug_core::errors::ButtplugDeviceError; 14use buttplug_server_device_config::Endpoint; 15use buttplug_server_device_config::{ 16 ProtocolCommunicationSpecifier, 17 ServerDeviceDefinition, 18 UserDeviceIdentifier, 19}; 20use std::sync::{ 21 Arc, 22 atomic::{AtomicU8, Ordering}, 23}; 24use uuid::{Uuid, uuid}; 25 26pub mod setup { 27 use crate::device::protocol::{ProtocolIdentifier, ProtocolIdentifierFactory}; 28 #[derive(Default)] 29 pub struct MonsterPubIdentifierFactory {} 30 31 impl ProtocolIdentifierFactory for MonsterPubIdentifierFactory { 32 fn identifier(&self) -> &str { 33 "monsterpub" 34 } 35 36 fn create(&self) -> Box<dyn ProtocolIdentifier> { 37 Box::new(super::MonsterPubIdentifier::default()) 38 } 39 } 40} 41 42const MONSTERPUB_PROTOCOL_UUID: Uuid = uuid!("c7fe6c69-e7c2-4fa9-822a-6bb337dece1a"); 43 44#[derive(Default)] 45pub struct MonsterPubIdentifier {} 46 47#[async_trait] 48impl ProtocolIdentifier for MonsterPubIdentifier { 49 async fn identify( 50 &mut self, 51 hardware: Arc<Hardware>, 52 _: ProtocolCommunicationSpecifier, 53 ) -> Result<(UserDeviceIdentifier, Box<dyn ProtocolInitializer>), ButtplugDeviceError> { 54 let read_resp = hardware 55 .read_value(&HardwareReadCmd::new( 56 MONSTERPUB_PROTOCOL_UUID, 57 Endpoint::RxBLEModel, 58 32, 59 500, 60 )) 61 .await; 62 let ident = match read_resp { 63 Ok(data) => std::str::from_utf8(data.data()) 64 .map_err(|_| { 65 ButtplugDeviceError::ProtocolSpecificError( 66 "monsterpub".to_owned(), 67 "MonsterPub device name is non-UTF8 string.".to_owned(), 68 ) 69 })? 70 .replace("\0", "") 71 .to_owned(), 72 Err(_) => "Unknown".to_string(), 73 }; 74 return Ok(( 75 UserDeviceIdentifier::new(hardware.address(), "monsterpub", &Some(ident)), 76 Box::new(MonsterPubInitializer::default()), 77 )); 78 } 79} 80 81#[derive(Default)] 82pub struct MonsterPubInitializer {} 83 84#[async_trait] 85impl ProtocolInitializer for MonsterPubInitializer { 86 async fn initialize( 87 &mut self, 88 hardware: Arc<Hardware>, 89 def: &ServerDeviceDefinition, 90 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 91 if hardware.endpoints().contains(&Endpoint::Rx) { 92 let value = hardware 93 .read_value(&HardwareReadCmd::new( 94 MONSTERPUB_PROTOCOL_UUID, 95 Endpoint::Rx, 96 16, 97 200, 98 )) 99 .await?; 100 let keys = [ 101 [ 102 0x32u8, 0x49, 0x50, 0x4f, 0x32, 0x49, 0x50, 0x4f, 0x32, 0x49, 0x50, 0x4f, 0x32, 0x49, 103 0x50, 104 ], 105 [ 106 0x4c, 0x53, 0x42, 0x42, 0x4c, 0x53, 0x42, 0x42, 0x4c, 0x53, 0x42, 0x42, 0x4c, 0x53, 0x42, 107 ], 108 [ 109 0x53, 0x49, 0x53, 0x36, 0x53, 0x49, 0x53, 0x36, 0x53, 0x49, 0x53, 0x36, 0x53, 0x49, 0x53, 110 ], 111 [ 112 0x54, 0x41, 0x4c, 0x4b, 0x54, 0x41, 0x4c, 0x4b, 0x54, 0x41, 0x4c, 0x4b, 0x54, 0x41, 0x4c, 113 ], 114 ]; 115 116 let auth = value.data()[1..16] 117 .iter() 118 .zip(keys[value.data()[0] as usize].iter()) 119 .map(|(&x1, &x2)| x1 ^ x2) 120 .collect(); 121 122 trace!( 123 "Got {:?} XOR with key {} to get {:?}", 124 value.data(), 125 value.data()[0], 126 auth 127 ); 128 129 hardware 130 .write_value(&HardwareWriteCmd::new( 131 &[MONSTERPUB_PROTOCOL_UUID], 132 Endpoint::Rx, 133 auth, 134 true, 135 )) 136 .await?; 137 } 138 let output_count = def 139 .features() 140 .iter() 141 .filter(|x| x.output().is_some()) 142 .count(); 143 144 Ok(Arc::new(MonsterPub::new( 145 if hardware.endpoints().contains(&Endpoint::TxVibrate) { 146 Endpoint::TxVibrate 147 } else if hardware.endpoints().contains(&Endpoint::Tx) { 148 Endpoint::Tx 149 } else { 150 Endpoint::Generic0 // tracy's dog 3 vibe 151 }, 152 output_count as u32, 153 ))) 154 } 155} 156 157pub struct MonsterPub { 158 tx: Endpoint, 159 speeds: Vec<AtomicU8>, 160} 161 162impl MonsterPub { 163 pub fn new(tx: Endpoint, num_outputs: u32) -> Self { 164 let speeds: Vec<AtomicU8> = std::iter::repeat_with(AtomicU8::default) 165 .take(num_outputs as usize) 166 .collect(); 167 Self { tx, speeds } 168 } 169 170 fn form_command(&self) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 171 let mut data = vec![]; 172 let mut stop = true; 173 174 if self.tx == Endpoint::Generic0 { 175 data.push(3u8); 176 } 177 for cmd in self.speeds.iter() { 178 let speed = cmd.load(Ordering::Relaxed); 179 data.push(speed); 180 if speed != 0 { 181 stop = false; 182 } 183 } 184 let tx = if self.tx == Endpoint::Tx && stop { 185 Endpoint::TxMode 186 } else { 187 self.tx 188 }; 189 Ok(vec![ 190 HardwareWriteCmd::new( 191 &[MONSTERPUB_PROTOCOL_UUID], 192 tx, 193 data, 194 tx == Endpoint::TxMode, 195 ) 196 .into(), 197 ]) 198 } 199} 200 201impl ProtocolHandler for MonsterPub { 202 fn handle_output_vibrate_cmd( 203 &self, 204 feature_index: u32, 205 _feature_id: Uuid, 206 speed: u32, 207 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 208 self.speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed); 209 self.form_command() 210 } 211 212 fn handle_output_oscillate_cmd( 213 &self, 214 feature_index: u32, 215 _feature_id: Uuid, 216 speed: u32, 217 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 218 self.speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed); 219 self.form_command() 220 } 221}