Buttplug sex toy control library
1// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2//
3// Copyright 2016-2023 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::protocol::ProtocolKeepaliveStrategy;
9use crate::device::{
10 hardware::{Hardware, HardwareCommand, HardwareSubscribeCmd, HardwareWriteCmd},
11 protocol::{
12 ProtocolHandler,
13 ProtocolIdentifier,
14 ProtocolInitializer,
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::sync::Arc;
27use uuid::{Uuid, uuid};
28
29generic_protocol_initializer_setup!(SvakomSam, "svakom-sam");
30const SVAKOM_SAM_PROTOCOL_UUID: Uuid = uuid!("e39a6b4a-230a-4669-be94-68135f97f166");
31
32#[derive(Default)]
33pub struct SvakomSamInitializer {}
34
35#[async_trait]
36impl ProtocolInitializer for SvakomSamInitializer {
37 async fn initialize(
38 &mut self,
39 hardware: Arc<Hardware>,
40 _: &ServerDeviceDefinition,
41 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> {
42 hardware
43 .subscribe(&HardwareSubscribeCmd::new(
44 SVAKOM_SAM_PROTOCOL_UUID,
45 Endpoint::Rx,
46 ))
47 .await?;
48 let mut gen2 = hardware.endpoints().contains(&Endpoint::TxMode);
49 if !gen2 && hardware.endpoints().contains(&Endpoint::Firmware) {
50 gen2 = true;
51 warn!(
52 "Svakom Sam model without speed control detected - This device will only vibrate at 1 speed"
53 );
54 }
55
56 Ok(Arc::new(SvakomSam::new(gen2)))
57 }
58}
59
60pub struct SvakomSam {
61 gen2: bool,
62}
63
64impl SvakomSam {
65 pub fn new(gen2: bool) -> Self {
66 Self { gen2 }
67 }
68}
69
70impl ProtocolHandler for SvakomSam {
71 fn keepalive_strategy(&self) -> ProtocolKeepaliveStrategy {
72 ProtocolKeepaliveStrategy::HardwareRequiredRepeatLastPacketStrategy
73 }
74
75 fn handle_output_vibrate_cmd(
76 &self,
77 feature_index: u32,
78 feature_id: Uuid,
79 speed: u32,
80 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
81 if feature_index == 0 {
82 Ok(vec![
83 HardwareWriteCmd::new(
84 &[feature_id],
85 Endpoint::Tx,
86 if self.gen2 {
87 [
88 18,
89 1,
90 3,
91 0,
92 if speed == 0 { 0x00 } else { 0x04 },
93 speed as u8,
94 ]
95 .to_vec()
96 } else {
97 [18, 1, 3, 0, 5, speed as u8].to_vec()
98 },
99 false,
100 )
101 .into(),
102 ])
103 } else {
104 Ok(vec![
105 HardwareWriteCmd::new(
106 &[feature_id],
107 Endpoint::Tx,
108 [18, 6, 1, speed as u8].to_vec(),
109 false,
110 )
111 .into(),
112 ])
113 }
114 }
115}