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 uuid::Uuid;
9
10use crate::device::{
11 hardware::{HardwareCommand, HardwareWriteCmd},
12 protocol::{ProtocolHandler, generic_protocol_setup},
13};
14use buttplug_core::errors::ButtplugDeviceError;
15use buttplug_server_device_config::Endpoint;
16use std::sync::{
17 Arc,
18 atomic::{AtomicU8, Ordering},
19};
20
21generic_protocol_setup!(ServeU, "serveu");
22
23#[derive(Default)]
24pub struct ServeU {
25 last_position: Arc<AtomicU8>,
26}
27
28impl ProtocolHandler for ServeU {
29 fn handle_position_with_duration_cmd(
30 &self,
31 _feature_index: u32,
32 feature_id: Uuid,
33 position: u32,
34 duration: u32,
35 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
36 let last_pos = self.last_position.load(Ordering::Relaxed);
37 // Need to get "units" (abstracted steps 0-100) per second, so calculate how far we need to move over our goal duration.
38 let goal_pos = position as u8;
39 self.last_position.store(goal_pos, Ordering::Relaxed);
40 let speed_threshold =
41 ((((goal_pos as i8) - last_pos as i8).abs()) as f64 / ((duration as f64) / 1000f64)).ceil();
42
43 let speed = if speed_threshold <= 0.00001 {
44 // Stop device
45 0
46 } else if speed_threshold <= 50.0 {
47 (speed_threshold / 2.0).ceil() as u8
48 } else if speed_threshold <= 750.0 {
49 ((speed_threshold - 50.0) / 4.0).ceil() as u8 + 25u8
50 } else if speed_threshold <= 2000.0 {
51 ((speed_threshold - 750.0) / 25.0).ceil() as u8 + 200u8
52 } else {
53 // If we're going faster than 2000u/s, just return max value (0xFA)
54 0xFA
55 };
56
57 Ok(vec![
58 HardwareWriteCmd::new(
59 &[feature_id],
60 Endpoint::Tx,
61 vec![0x01, goal_pos, speed],
62 false,
63 )
64 .into(),
65 ])
66 }
67}