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 crate::device::{
9 hardware::{Hardware, HardwareCommand, HardwareWriteCmd},
10 protocol::{
11 ProtocolHandler,
12 ProtocolIdentifier,
13 ProtocolInitializer,
14 generic_protocol_initializer_setup,
15 },
16};
17use async_trait::async_trait;
18use buttplug_core::errors::ButtplugDeviceError;
19use buttplug_core::message::OutputType;
20use buttplug_server_device_config::Endpoint;
21use buttplug_server_device_config::{
22 ProtocolCommunicationSpecifier,
23 ServerDeviceDefinition,
24 UserDeviceIdentifier,
25};
26use std::sync::Arc;
27use std::sync::atomic::{AtomicU8, Ordering};
28use uuid::{Uuid, uuid};
29
30const WEVIBE_PROTOCOL_UUID: Uuid = uuid!("3658e33d-086d-401e-9dce-8e9e88ff791f");
31generic_protocol_initializer_setup!(WeVibe, "wevibe");
32
33#[derive(Default)]
34pub struct WeVibeInitializer {}
35
36#[async_trait]
37impl ProtocolInitializer for WeVibeInitializer {
38 async fn initialize(
39 &mut self,
40 hardware: Arc<Hardware>,
41 def: &ServerDeviceDefinition,
42 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> {
43 debug!("calling WeVibe init");
44 hardware
45 .write_value(&HardwareWriteCmd::new(
46 &[WEVIBE_PROTOCOL_UUID],
47 Endpoint::Tx,
48 vec![0x0f, 0x03, 0x00, 0x99, 0x00, 0x03, 0x00, 0x00],
49 true,
50 ))
51 .await?;
52 hardware
53 .write_value(&HardwareWriteCmd::new(
54 &[WEVIBE_PROTOCOL_UUID],
55 Endpoint::Tx,
56 vec![0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
57 true,
58 ))
59 .await?;
60 let num_vibrators = def
61 .features()
62 .iter()
63 .filter(|x| {
64 x.output()
65 .as_ref()
66 .is_some_and(|x| x.contains(OutputType::Vibrate))
67 })
68 .count() as u8;
69 Ok(Arc::new(WeVibe::new(num_vibrators)))
70 }
71}
72
73pub struct WeVibe {
74 num_vibrators: u8,
75 speeds: [AtomicU8; 2],
76}
77
78impl WeVibe {
79 fn new(num_vibrators: u8) -> Self {
80 Self {
81 num_vibrators,
82 speeds: [AtomicU8::default(), AtomicU8::default()],
83 }
84 }
85}
86
87impl ProtocolHandler for WeVibe {
88 fn handle_output_vibrate_cmd(
89 &self,
90 feature_index: u32,
91 _feature_id: uuid::Uuid,
92 speed: u32,
93 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
94 self.speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed);
95 let max_vibrators = if self.num_vibrators > 1 { 1 } else { 0 };
96 let r_speed_int = self.speeds[0].load(Ordering::Relaxed);
97 let r_speed_ext = self.speeds[max_vibrators].load(Ordering::Relaxed);
98 let data = if r_speed_int == 0 && r_speed_ext == 0 {
99 vec![0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
100 } else {
101 vec![
102 0x0f,
103 0x03,
104 0x00,
105 r_speed_ext | (r_speed_int << 4),
106 0x00,
107 0x03,
108 0x00,
109 0x00,
110 ]
111 };
112 Ok(vec![
113 HardwareWriteCmd::new(&[WEVIBE_PROTOCOL_UUID], Endpoint::Tx, data, true).into(),
114 ])
115 }
116}