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 buttplug_core::errors::ButtplugDeviceError; 9use buttplug_server_device_config::Endpoint; 10use buttplug_server_device_config::{ 11 ProtocolCommunicationSpecifier, 12 ServerDeviceDefinition, 13 UserDeviceIdentifier, 14}; 15 16use crate::device::{ 17 hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, 18 protocol::{ProtocolHandler, ProtocolIdentifier, ProtocolInitializer}, 19}; 20use async_trait::async_trait; 21use std::sync::{ 22 Arc, 23 atomic::{AtomicU8, Ordering}, 24}; 25use uuid::Uuid; 26 27pub mod setup { 28 use crate::device::protocol::{ProtocolIdentifier, ProtocolIdentifierFactory}; 29 #[derive(Default)] 30 pub struct YououIdentifierFactory {} 31 32 impl ProtocolIdentifierFactory for YououIdentifierFactory { 33 fn identifier(&self) -> &str { 34 "youou" 35 } 36 37 fn create(&self) -> Box<dyn ProtocolIdentifier> { 38 Box::new(super::YououIdentifier::default()) 39 } 40 } 41} 42 43#[derive(Default)] 44pub struct YououIdentifier {} 45 46#[async_trait] 47impl ProtocolIdentifier for YououIdentifier { 48 async fn identify( 49 &mut self, 50 hardware: Arc<Hardware>, 51 _: ProtocolCommunicationSpecifier, 52 ) -> Result<(UserDeviceIdentifier, Box<dyn ProtocolInitializer>), ButtplugDeviceError> { 53 Ok(( 54 UserDeviceIdentifier::new(hardware.address(), "Youou", &Some("VX001_".to_owned())), 55 Box::new(YououInitializer::default()), 56 )) 57 } 58} 59 60#[derive(Default)] 61pub struct YououInitializer {} 62 63#[async_trait] 64impl ProtocolInitializer for YououInitializer { 65 async fn initialize( 66 &mut self, 67 _: Arc<Hardware>, 68 _: &ServerDeviceDefinition, 69 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 70 Ok(Arc::new(Youou::default())) 71 } 72} 73 74#[derive(Default)] 75pub struct Youou { 76 packet_id: AtomicU8, 77} 78 79impl ProtocolHandler for Youou { 80 fn handle_output_vibrate_cmd( 81 &self, 82 _feature_index: u32, 83 feature_id: Uuid, 84 speed: u32, 85 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 86 // Byte 2 seems to be a monotonically increasing packet id of some kind 87 // 88 // Speed seems to be 0-247 or so. 89 // 90 // Anything above that sets a pattern which isn't what we want here. 91 let state = u8::from(speed > 0); 92 93 // Scope the packet id set so we can unlock ASAP. 94 let mut data = vec![ 95 0xaa, 96 0x55, 97 self.packet_id.load(Ordering::Relaxed), 98 0x02, 99 0x03, 100 0x01, 101 speed as u8, 102 state, 103 ]; 104 self.packet_id.store( 105 self.packet_id.load(Ordering::Relaxed).wrapping_add(1), 106 Ordering::Relaxed, 107 ); 108 let mut crc: u8 = 0; 109 110 // Simple XOR of everything up to the 9th byte for CRC. 111 for b in data.clone() { 112 crc ^= b; 113 } 114 115 let mut data2 = vec![crc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 116 data.append(&mut data2); 117 118 Ok(vec![ 119 HardwareWriteCmd::new(&[feature_id], Endpoint::Tx, data, false).into(), 120 ]) 121 } 122}