Buttplug sex toy control library
at dev 5.5 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, message::OutputType}; 14use buttplug_server_device_config::{ 15 Endpoint, 16 ProtocolCommunicationSpecifier, 17 ServerDeviceDefinition, 18 UserDeviceIdentifier, 19}; 20use std::sync::Arc; 21use uuid::{Uuid, uuid}; 22 23const HISMITH_MINI_PROTOCOL_UUID: Uuid = uuid!("94befc1a-9859-4bf6-99ee-5678c89237a7"); 24const HISMITH_MINI_ROTATE_DIRECTIOM_UUID: Uuid = uuid!("94befc1a-9859-4bf6-99ee-5678c89237a7"); 25 26pub mod setup { 27 use crate::device::protocol::{ProtocolIdentifier, ProtocolIdentifierFactory}; 28 #[derive(Default)] 29 pub struct HismithMiniIdentifierFactory {} 30 31 impl ProtocolIdentifierFactory for HismithMiniIdentifierFactory { 32 fn identifier(&self) -> &str { 33 "hismith-mini" 34 } 35 36 fn create(&self) -> Box<dyn ProtocolIdentifier> { 37 Box::new(super::HismithMiniIdentifier::default()) 38 } 39 } 40} 41 42#[derive(Default)] 43pub struct HismithMiniIdentifier {} 44 45#[async_trait] 46impl ProtocolIdentifier for HismithMiniIdentifier { 47 async fn identify( 48 &mut self, 49 hardware: Arc<Hardware>, 50 _: ProtocolCommunicationSpecifier, 51 ) -> Result<(UserDeviceIdentifier, Box<dyn ProtocolInitializer>), ButtplugDeviceError> { 52 let result = hardware 53 .read_value(&HardwareReadCmd::new( 54 HISMITH_MINI_PROTOCOL_UUID, 55 Endpoint::RxBLEModel, 56 128, 57 500, 58 )) 59 .await?; 60 61 let identifier = result 62 .data() 63 .iter() 64 .map(|b| format!("{b:02x}")) 65 .collect::<String>(); 66 info!("Hismith Device Identifier: {}", identifier); 67 68 Ok(( 69 UserDeviceIdentifier::new(hardware.address(), "hismith-mini", &Some(identifier)), 70 Box::new(HismithMiniInitializer::default()), 71 )) 72 } 73} 74 75#[derive(Default)] 76pub struct HismithMiniInitializer {} 77 78#[async_trait] 79impl ProtocolInitializer for HismithMiniInitializer { 80 async fn initialize( 81 &mut self, 82 _: Arc<Hardware>, 83 device_definition: &ServerDeviceDefinition, 84 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 85 Ok(Arc::new(HismithMini { 86 dual_vibe: device_definition 87 .features() 88 .iter() 89 .filter(|x| { 90 x.output() 91 .as_ref() 92 .is_some_and(|x| x.contains(OutputType::Vibrate)) 93 }) 94 .count() 95 >= 2, 96 second_constrict: device_definition 97 .features() 98 .iter() 99 .position(|x| { 100 x.output() 101 .as_ref() 102 .is_some_and(|x| x.contains(OutputType::Constrict)) 103 }) 104 .unwrap_or(0) 105 == 1, 106 })) 107 } 108} 109 110#[derive(Default)] 111pub struct HismithMini { 112 dual_vibe: bool, 113 second_constrict: bool, 114} 115 116impl ProtocolHandler for HismithMini { 117 fn handle_output_oscillate_cmd( 118 &self, 119 _feature_index: u32, 120 feature_id: Uuid, 121 speed: u32, 122 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 123 let idx: u8 = 0x03; 124 let speed: u8 = speed as u8; 125 126 Ok(vec![ 127 HardwareWriteCmd::new( 128 &[feature_id], 129 Endpoint::Tx, 130 vec![0xCC, idx, speed, speed + idx], 131 false, 132 ) 133 .into(), 134 ]) 135 } 136 137 fn handle_output_vibrate_cmd( 138 &self, 139 feature_index: u32, 140 feature_id: Uuid, 141 speed: u32, 142 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 143 let idx: u8 = if !self.dual_vibe || feature_index == 1 { 144 0x05 145 } else { 146 0x03 147 }; 148 let speed: u8 = speed as u8; 149 150 Ok(vec![ 151 HardwareWriteCmd::new( 152 &[feature_id], 153 Endpoint::Tx, 154 vec![0xCC, idx, speed, speed + idx], 155 false, 156 ) 157 .into(), 158 ]) 159 } 160 161 fn handle_output_constrict_cmd( 162 &self, 163 _feature_index: u32, 164 feature_id: Uuid, 165 level: u32, 166 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 167 let idx: u8 = if self.second_constrict { 0x05 } else { 0x03 }; 168 let speed: u8 = level as u8; 169 170 Ok(vec![ 171 HardwareWriteCmd::new( 172 &[feature_id], 173 Endpoint::Tx, 174 vec![0xCC, idx, speed, speed + idx], 175 false, 176 ) 177 .into(), 178 ]) 179 } 180 181 fn handle_output_rotate_cmd( 182 &self, 183 _feature_index: u32, 184 feature_id: Uuid, 185 speed: i32, 186 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 187 Ok(vec![ 188 HardwareWriteCmd::new( 189 &[feature_id], 190 Endpoint::Tx, 191 vec![ 192 0xCC, 193 0x03, 194 speed.unsigned_abs() as u8, 195 speed.unsigned_abs() as u8 + 3, 196 ], 197 false, 198 ) 199 .into(), 200 HardwareWriteCmd::new( 201 &[HISMITH_MINI_ROTATE_DIRECTIOM_UUID], 202 Endpoint::Tx, 203 vec![ 204 0xCC, 205 0x01, 206 if speed >= 0 { 0xc0 } else { 0xc1 }, 207 if speed >= 0 { 0xc1 } else { 0xc2 }, 208 ], 209 false, 210 ) 211 .into(), 212 ]) 213 } 214 215 fn handle_output_spray_cmd( 216 &self, 217 _feature_index: u32, 218 feature_id: Uuid, 219 _level: u32, 220 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 221 Ok(vec![ 222 HardwareWriteCmd::new( 223 &[feature_id], 224 Endpoint::Tx, 225 vec![0xcc, 0x0b, 0x01, 0x0c], 226 false, 227 ) 228 .into(), 229 ]) 230 } 231}