Buttplug sex toy control library
at dev 3.9 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 super::hismith_mini::HismithMiniInitializer; 9use crate::device::{ 10 hardware::{Hardware, HardwareCommand, HardwareReadCmd, HardwareWriteCmd}, 11 protocol::{ProtocolHandler, ProtocolIdentifier, ProtocolInitializer}, 12}; 13use async_trait::async_trait; 14use buttplug_core::errors::ButtplugDeviceError; 15use buttplug_server_device_config::Endpoint; 16use buttplug_server_device_config::{ 17 ProtocolCommunicationSpecifier, 18 ServerDeviceDefinition, 19 UserDeviceIdentifier, 20}; 21use std::sync::Arc; 22use uuid::{Uuid, uuid}; 23 24const HISMITH_PROTOCOL_UUID: Uuid = uuid!("e59f9c5d-bb4a-4a9c-ab57-0ceb43af1da7"); 25 26pub mod setup { 27 use crate::device::protocol::{ProtocolIdentifier, ProtocolIdentifierFactory}; 28 #[derive(Default)] 29 pub struct HismithIdentifierFactory {} 30 31 impl ProtocolIdentifierFactory for HismithIdentifierFactory { 32 fn identifier(&self) -> &str { 33 "hismith" 34 } 35 36 fn create(&self) -> Box<dyn ProtocolIdentifier> { 37 Box::new(super::HismithIdentifier::default()) 38 } 39 } 40} 41 42#[derive(Default)] 43pub struct HismithIdentifier {} 44 45const LEGACY_HISMITHS: [&str; 6] = ["1001", "1002", "1003", "3001", "2001", "1006"]; 46 47#[async_trait] 48impl ProtocolIdentifier for HismithIdentifier { 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 HISMITH_PROTOCOL_UUID, 57 Endpoint::RxBLEModel, 58 128, 59 500, 60 )) 61 .await?; 62 63 let identifier = result 64 .data() 65 .iter() 66 .map(|b| format!("{b:02x}")) 67 .collect::<String>(); 68 info!("Hismith Device Identifier: {}", identifier); 69 70 if !LEGACY_HISMITHS.contains(&identifier.as_str()) { 71 info!("Not a legacy Hismith, using hismith-mini protocol"); 72 return Ok(( 73 UserDeviceIdentifier::new(hardware.address(), "hismith-mini", &Some(identifier)), 74 Box::new(HismithMiniInitializer::default()), 75 )); 76 } 77 78 Ok(( 79 UserDeviceIdentifier::new(hardware.address(), "hismith", &Some(identifier)), 80 Box::new(HismithInitializer::default()), 81 )) 82 } 83} 84 85#[derive(Default)] 86pub struct HismithInitializer {} 87 88#[async_trait] 89impl ProtocolInitializer for HismithInitializer { 90 async fn initialize( 91 &mut self, 92 _: Arc<Hardware>, 93 _: &ServerDeviceDefinition, 94 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 95 Ok(Arc::new(Hismith::default())) 96 } 97} 98 99#[derive(Default)] 100pub struct Hismith {} 101 102impl ProtocolHandler for Hismith { 103 fn handle_output_oscillate_cmd( 104 &self, 105 _feature_index: u32, 106 feature_id: Uuid, 107 speed: u32, 108 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 109 let idx: u8 = 0x04; 110 let speed: u8 = speed as u8; 111 112 Ok(vec![ 113 HardwareWriteCmd::new( 114 &[feature_id], 115 Endpoint::Tx, 116 vec![0xAA, idx, speed, speed + idx], 117 false, 118 ) 119 .into(), 120 ]) 121 } 122 123 fn handle_output_vibrate_cmd( 124 &self, 125 feature_index: u32, 126 feature_id: Uuid, 127 speed: u32, 128 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 129 // Wildolo has a vibe at index 0 using id 4 130 // The thrusting stroker has a vibe at index 1 using id 6 (and the weird 0xf0 off) 131 let idx: u8 = if feature_index == 0 { 0x04 } else { 0x06 }; 132 let speed: u8 = if feature_index != 0 && speed == 0 { 133 0xf0 134 } else { 135 speed as u8 136 }; 137 138 Ok(vec![ 139 HardwareWriteCmd::new( 140 &[feature_id], 141 Endpoint::Tx, 142 vec![0xAA, idx, speed, speed + idx], 143 false, 144 ) 145 .into(), 146 ]) 147 } 148}