Buttplug sex toy control library
at master 143 lines 3.5 kB view raw
1// Buttplug Rust Source Code File - See https://buttplug.io for more info. 2// 3// Copyright 2016-2025 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 async_trait::async_trait; 9use uuid::{Uuid, uuid}; 10 11use buttplug_core::{errors::ButtplugDeviceError, message::OutputType}; 12 13use crate::device::{ 14 hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, 15 protocol::{ 16 ProtocolHandler, 17 ProtocolIdentifier, 18 ProtocolInitializer, 19 ProtocolKeepaliveStrategy, 20 generic_protocol_initializer_setup, 21 }, 22}; 23use buttplug_server_device_config::{ 24 Endpoint, 25 ProtocolCommunicationSpecifier, 26 ServerDeviceDefinition, 27 UserDeviceIdentifier, 28}; 29use std::sync::{ 30 Arc, 31 atomic::{AtomicU8, Ordering}, 32}; 33 34const SVAKOM_V6_VIBRATOR_UUID: Uuid = uuid!("4cf33d95-a3d1-4ed4-9ac6-9ba6d6ccb091"); 35 36generic_protocol_initializer_setup!(SvakomV6, "svakom-v6"); 37 38#[derive(Default)] 39pub struct SvakomV6Initializer {} 40 41#[async_trait] 42impl ProtocolInitializer for SvakomV6Initializer { 43 async fn initialize( 44 &mut self, 45 _: Arc<Hardware>, 46 def: &ServerDeviceDefinition, 47 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 48 let num_vibrators = def 49 .features() 50 .iter() 51 .filter(|x| { 52 if let Some(output_map) = x.output() { 53 output_map.contains(OutputType::Vibrate) 54 } else { 55 false 56 } 57 }) 58 .count() as u8; 59 Ok(Arc::new(SvakomV6::new(num_vibrators))) 60 } 61} 62 63#[derive(Default)] 64pub struct SvakomV6 { 65 num_vibrators: u8, 66 last_vibrator_speeds: [AtomicU8; 3], 67} 68 69impl SvakomV6 { 70 fn new(num_vibrators: u8) -> Self { 71 Self { 72 num_vibrators, 73 ..Default::default() 74 } 75 } 76} 77 78impl ProtocolHandler for SvakomV6 { 79 fn keepalive_strategy(&self) -> ProtocolKeepaliveStrategy { 80 ProtocolKeepaliveStrategy::HardwareRequiredRepeatLastPacketStrategy 81 } 82 83 fn handle_output_vibrate_cmd( 84 &self, 85 feature_index: u32, 86 feature_id: uuid::Uuid, 87 speed: u32, 88 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 89 self.last_vibrator_speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed); 90 if feature_index < 2 { 91 let vibe1 = self.last_vibrator_speeds[0].load(Ordering::Relaxed); 92 let vibe2 = self.last_vibrator_speeds[1].load(Ordering::Relaxed); 93 Ok(vec![ 94 HardwareWriteCmd::new( 95 &[SVAKOM_V6_VIBRATOR_UUID], 96 Endpoint::Tx, 97 [ 98 0x55, 99 0x03, 100 if self.num_vibrators == 1 || (vibe1 > 0 && vibe2 > 0) || vibe1 == vibe2 { 101 0x00 102 } else if vibe1 > 0 { 103 0x01 104 } else { 105 0x02 106 }, 107 0x00, 108 if vibe1 == vibe2 && vibe1 == 0 { 109 0x00 110 } else { 111 0x01 112 }, 113 { vibe1.max(vibe2) }, 114 0x00, 115 ] 116 .to_vec(), 117 false, 118 ) 119 .into(), 120 ]) 121 } else { 122 let vibe3 = self.last_vibrator_speeds[2].load(Ordering::Relaxed); 123 Ok(vec![ 124 HardwareWriteCmd::new( 125 &[feature_id], 126 Endpoint::Tx, 127 [ 128 0x55, 129 0x07, 130 0x00, 131 0x00, 132 if vibe3 == 0 { 0x00 } else { 0x01 }, 133 { vibe3 }, 134 0x00, 135 ] 136 .to_vec(), 137 false, 138 ) 139 .into(), 140 ]) 141 } 142 } 143}