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, HardwareSubscribeCmd, 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_server_device_config::Endpoint;
20use buttplug_server_device_config::{
21 ProtocolCommunicationSpecifier,
22 ServerDeviceDefinition,
23 UserDeviceIdentifier,
24};
25use std::sync::{
26 Arc,
27 atomic::{AtomicU8, Ordering},
28};
29use uuid::{Uuid, uuid};
30
31const LELO_F1S_PROTOCOL_UUID: Uuid = uuid!("4987f232-40f9-47a3-8d0c-e30b74e75310");
32generic_protocol_initializer_setup!(LeloF1s, "lelo-f1s");
33
34#[derive(Default)]
35pub struct LeloF1sInitializer {}
36
37#[async_trait]
38impl ProtocolInitializer for LeloF1sInitializer {
39 async fn initialize(
40 &mut self,
41 hardware: Arc<Hardware>,
42 _: &ServerDeviceDefinition,
43 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> {
44 // The Lelo F1s needs you to hit the power button after connection
45 // before it'll accept any commands. Unless we listen for event on
46 // the button, this is more likely to turn the device off.
47 hardware
48 .subscribe(&HardwareSubscribeCmd::new(
49 LELO_F1S_PROTOCOL_UUID,
50 Endpoint::Rx,
51 ))
52 .await?;
53 Ok(Arc::new(LeloF1s::new(false)))
54 }
55}
56
57pub struct LeloF1s {
58 speeds: [AtomicU8; 2],
59 write_with_response: bool,
60}
61
62impl LeloF1s {
63 pub fn new(write_with_response: bool) -> Self {
64 Self {
65 write_with_response,
66 speeds: [AtomicU8::new(0), AtomicU8::new(0)],
67 }
68 }
69}
70
71impl ProtocolHandler for LeloF1s {
72 fn handle_output_vibrate_cmd(
73 &self,
74 feature_index: u32,
75 _feature_id: Uuid,
76 speed: u32,
77 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
78 self.speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed);
79 let mut cmd_vec = vec![0x1];
80 self
81 .speeds
82 .iter()
83 .for_each(|v| cmd_vec.push(v.load(Ordering::Relaxed)));
84 Ok(vec![
85 HardwareWriteCmd::new(
86 &[LELO_F1S_PROTOCOL_UUID],
87 Endpoint::Tx,
88 cmd_vec,
89 self.write_with_response,
90 )
91 .into(),
92 ])
93 }
94}