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 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!(WeVibe8Bit, "wevibe-8bit");
34
35const WEVIBE8BIT_PROTOCOL_UUID: Uuid = uuid!("f5e48973-09e9-4063-8177-487f6292e2ed");
36
37#[derive(Default)]
38pub struct WeVibe8BitInitializer {}
39
40#[async_trait]
41impl ProtocolInitializer for WeVibe8BitInitializer {
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(WeVibe8Bit::new(num_vibrators)))
57 }
58}
59
60pub struct WeVibe8Bit {
61 num_vibrators: u8,
62 speeds: [AtomicU8; 2],
63}
64
65impl WeVibe8Bit {
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 WeVibe8Bit {
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 let status_byte: u8 =
89 (if r_speed_ext == 0 { 0 } else { 2 }) | (if r_speed_int == 0 { 0 } else { 1 });
90 vec![
91 0x0f,
92 0x03,
93 0x00,
94 r_speed_ext + 3,
95 r_speed_int + 3,
96 status_byte,
97 0x00,
98 0x00,
99 ]
100 };
101 Ok(vec![
102 HardwareWriteCmd::new(&[WEVIBE8BIT_PROTOCOL_UUID], Endpoint::Tx, data, true).into(),
103 ])
104 }
105}