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 ProtocolKeepaliveStrategy,
15 generic_protocol_initializer_setup,
16 },
17};
18use async_trait::async_trait;
19use buttplug_core::errors::ButtplugDeviceError;
20use buttplug_server_device_config::Endpoint;
21use buttplug_server_device_config::{
22 ProtocolCommunicationSpecifier,
23 ServerDeviceDefinition,
24 UserDeviceIdentifier,
25};
26use std::{
27 sync::{
28 Arc,
29 atomic::{AtomicU8, Ordering},
30 },
31 time::Duration,
32};
33use uuid::{Uuid, uuid};
34
35generic_protocol_initializer_setup!(MysteryVibe, "mysteryvibe");
36
37const MYSTERYVIBE_PROTOCOL_UUID: Uuid = uuid!("53bca658-2efe-4388-8ced-333789bac20b");
38
39#[derive(Default)]
40pub struct MysteryVibeInitializer {}
41
42#[async_trait]
43impl ProtocolInitializer for MysteryVibeInitializer {
44 async fn initialize(
45 &mut self,
46 hardware: Arc<Hardware>,
47 def: &ServerDeviceDefinition,
48 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> {
49 let msg = HardwareWriteCmd::new(
50 &[MYSTERYVIBE_PROTOCOL_UUID],
51 Endpoint::TxMode,
52 vec![0x43u8, 0x02u8, 0x00u8],
53 true,
54 );
55 hardware.write_value(&msg).await?;
56 let vibrator_count = def
57 .features()
58 .iter()
59 .filter(|x| x.output().is_some())
60 .count();
61 Ok(Arc::new(MysteryVibe::new(vibrator_count as u8)))
62 }
63}
64
65// Time between Mysteryvibe update commands, in milliseconds. This is basically
66// a best guess derived from watching packet timing a few years ago.
67//
68// Thelemic vibrator. Neat.
69//
70const MYSTERYVIBE_COMMAND_DELAY_MS: u64 = 93;
71
72#[derive(Default)]
73pub struct MysteryVibe {
74 speeds: Vec<AtomicU8>,
75}
76
77impl MysteryVibe {
78 pub fn new(vibrator_count: u8) -> Self {
79 Self {
80 speeds: std::iter::repeat_with(AtomicU8::default)
81 .take(vibrator_count as usize)
82 .collect(),
83 }
84 }
85}
86
87impl ProtocolHandler for MysteryVibe {
88 fn keepalive_strategy(&self) -> ProtocolKeepaliveStrategy {
89 ProtocolKeepaliveStrategy::RepeatLastPacketStrategyWithTiming(Duration::from_millis(
90 MYSTERYVIBE_COMMAND_DELAY_MS,
91 ))
92 }
93
94 fn handle_output_vibrate_cmd(
95 &self,
96 feature_index: u32,
97 _feature_id: Uuid,
98 speed: u32,
99 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
100 self.speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed);
101 Ok(vec![
102 HardwareWriteCmd::new(
103 &[MYSTERYVIBE_PROTOCOL_UUID],
104 Endpoint::TxVibrate,
105 self
106 .speeds
107 .iter()
108 .map(|x| x.load(Ordering::Relaxed))
109 .collect(),
110 false,
111 )
112 .into(),
113 ])
114 }
115}