Buttplug sex toy control library
at dev 2.8 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 std::sync::{ 9 Arc, 10 atomic::{AtomicU8, Ordering}, 11}; 12 13use async_trait::async_trait; 14use uuid::{Uuid, uuid}; 15 16use crate::device::{ 17 hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, 18 protocol::{ 19 ProtocolHandler, 20 ProtocolIdentifier, 21 ProtocolInitializer, 22 generic_protocol_initializer_setup, 23 }, 24}; 25use buttplug_core::{errors::ButtplugDeviceError, message::OutputType}; 26use buttplug_server_device_config::{ 27 Endpoint, 28 ProtocolCommunicationSpecifier, 29 ServerDeviceDefinition, 30 UserDeviceIdentifier, 31}; 32 33generic_protocol_initializer_setup!(WeVibeChorus, "wevibe-chorus"); 34 35const WEVIBE_CHORUS_PROTOCOL_UUID: Uuid = uuid!("cdeadd1c-b913-4305-a255-bd8834c4e37f"); 36 37#[derive(Default)] 38pub struct WeVibeChorusInitializer {} 39 40#[async_trait] 41impl ProtocolInitializer for WeVibeChorusInitializer { 42 async fn initialize( 43 &mut self, 44 _hardware: Arc<Hardware>, 45 def: &ServerDeviceDefinition, 46 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 47 let num_vibrators = def 48 .features() 49 .iter() 50 .filter(|x| { 51 x.output() 52 .as_ref() 53 .is_some_and(|x| x.contains(OutputType::Vibrate)) 54 }) 55 .count() as u8; 56 Ok(Arc::new(WeVibeChorus::new(num_vibrators))) 57 } 58} 59 60pub struct WeVibeChorus { 61 num_vibrators: u8, 62 speeds: [AtomicU8; 2], 63} 64 65impl WeVibeChorus { 66 fn new(num_vibrators: u8) -> Self { 67 Self { 68 num_vibrators, 69 speeds: [AtomicU8::default(), AtomicU8::default()], 70 } 71 } 72} 73 74impl ProtocolHandler for WeVibeChorus { 75 fn handle_output_vibrate_cmd( 76 &self, 77 feature_index: u32, 78 _feature_id: uuid::Uuid, 79 speed: u32, 80 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 81 self.speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed); 82 let max_vibrators = if self.num_vibrators > 1 { 1 } else { 0 }; 83 let r_speed_int = self.speeds[0].load(Ordering::Relaxed); 84 let r_speed_ext = self.speeds[max_vibrators].load(Ordering::Relaxed); 85 let data = if r_speed_int == 0 && r_speed_ext == 0 { 86 vec![0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 87 } else { 88 // Note the motor order is flipped for the Chorus 89 let status_byte: u8 = 90 (if r_speed_ext == 0 { 0 } else { 2 }) | (if r_speed_int == 0 { 0 } else { 1 }); 91 vec![ 92 0x0f, 93 0x03, 94 0x00, 95 r_speed_int, 96 r_speed_ext, 97 status_byte, 98 0x00, 99 0x00, 100 ] 101 }; 102 Ok(vec![ 103 HardwareWriteCmd::new(&[WEVIBE_CHORUS_PROTOCOL_UUID], Endpoint::Tx, data, true).into(), 104 ]) 105 } 106}