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 uuid::{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::num::Wrapping;
17use std::sync::atomic::{AtomicU8, Ordering};
18
19static KEY_TAB: [[u8; 12]; 4] = [
20 [0, 24, 0x98, 0xf7, 0xa5, 61, 13, 41, 37, 80, 68, 70],
21 [0, 69, 110, 106, 111, 120, 32, 83, 45, 49, 46, 55],
22 [0, 101, 120, 32, 84, 111, 121, 115, 10, 0x8e, 0x9d, 0xa3],
23 [0, 0xc5, 0xd6, 0xe7, 0xf8, 10, 50, 32, 111, 98, 13, 10],
24];
25
26const GALAKU_PUMP_PROTOCOL_UUID: Uuid = uuid!("165ae3a9-33be-46a8-b438-9a6fc0f183cb");
27generic_protocol_setup!(GalakuPump, "galaku-pump");
28
29pub struct GalakuPump {
30 speeds: [AtomicU8; 2],
31}
32
33impl Default for GalakuPump {
34 fn default() -> Self {
35 Self {
36 speeds: [AtomicU8::new(0), AtomicU8::new(0)],
37 }
38 }
39}
40
41impl GalakuPump {
42 fn hardware_command(&self) -> Vec<HardwareCommand> {
43 let mut data: Vec<u8> = vec![
44 0x23,
45 0x5a,
46 0x00,
47 0x00,
48 0x01,
49 0x60,
50 0x03,
51 self.speeds[0].load(Ordering::Relaxed),
52 self.speeds[1].load(Ordering::Relaxed),
53 0x00,
54 0x00,
55 ];
56 data.push(data.iter().fold(0u8, |c, b| (Wrapping(c) + Wrapping(*b)).0));
57
58 let mut data2: Vec<u8> = vec![0x23];
59 for i in 1..data.len() {
60 let k = KEY_TAB[(data2[i - 1] & 3) as usize][i];
61 data2.push((Wrapping((k ^ 0x23) ^ data[i]) + Wrapping(k)).0);
62 }
63
64 vec![HardwareWriteCmd::new(&[GALAKU_PUMP_PROTOCOL_UUID], Endpoint::Tx, data2, true).into()]
65 }
66}
67
68impl ProtocolHandler for GalakuPump {
69 fn handle_output_oscillate_cmd(
70 &self,
71 _feature_index: u32,
72 _feature_id: Uuid,
73 speed: u32,
74 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
75 self.speeds[0].store(speed as u8, Ordering::Relaxed);
76 Ok(self.hardware_command())
77 }
78
79 fn handle_output_vibrate_cmd(
80 &self,
81 _feature_index: u32,
82 _feature_id: Uuid,
83 speed: u32,
84 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
85 self.speeds[1].store(speed as u8, Ordering::Relaxed);
86 Ok(self.hardware_command())
87 }
88}