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;
26use buttplug_server_device_config::Endpoint;
27use buttplug_server_device_config::ServerDeviceDefinition;
28use buttplug_server_device_config::{ProtocolCommunicationSpecifier, UserDeviceIdentifier};
29const MAGICMOTIONV4_PROTOCOL_UUID: Uuid = uuid!("d4d62d09-c3e1-44c9-8eba-caa15de5b2a7");
30
31generic_protocol_initializer_setup!(MagicMotionV4, "magic-motion-4");
32
33#[derive(Default)]
34pub struct MagicMotionV4Initializer {}
35
36#[async_trait]
37impl ProtocolInitializer for MagicMotionV4Initializer {
38 async fn initialize(
39 &mut self,
40 _: Arc<Hardware>,
41 def: &ServerDeviceDefinition,
42 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> {
43 Ok(Arc::new(MagicMotionV4::new(
44 def
45 .features()
46 .iter()
47 .filter(|x| x.output().is_some())
48 .count() as u8,
49 )))
50 }
51}
52
53pub struct MagicMotionV4 {
54 current_commands: Vec<AtomicU8>,
55}
56
57impl MagicMotionV4 {
58 fn new(num_vibrators: u8) -> Self {
59 Self {
60 current_commands: std::iter::repeat_with(AtomicU8::default)
61 .take(num_vibrators as usize)
62 .collect(),
63 }
64 }
65}
66
67impl ProtocolHandler for MagicMotionV4 {
68 fn handle_output_vibrate_cmd(
69 &self,
70 feature_index: u32,
71 _feature_id: Uuid,
72 speed: u32,
73 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
74 let data = if self.current_commands.len() == 1 {
75 vec![
76 0x10,
77 0xff,
78 0x04,
79 0x0a,
80 0x32,
81 0x32,
82 0x00,
83 0x04,
84 0x08,
85 speed as u8,
86 0x64,
87 0x00,
88 0x04,
89 0x08,
90 speed as u8,
91 0x64,
92 0x01,
93 ]
94 } else {
95 self.current_commands[feature_index as usize].store(speed as u8, Ordering::Relaxed);
96 let speed0 = self.current_commands[0].load(Ordering::Relaxed);
97 let speed1 = self.current_commands[1].load(Ordering::Relaxed);
98 vec![
99 0x10, 0xff, 0x04, 0x0a, 0x32, 0x32, 0x00, 0x04, 0x08, speed0, 0x64, 0x00, 0x04, 0x08,
100 speed1, 0x64, 0x01,
101 ]
102 };
103 Ok(vec![
104 HardwareWriteCmd::new(&[MAGICMOTIONV4_PROTOCOL_UUID], Endpoint::Tx, data, true).into(),
105 ])
106 }
107}