Buttplug sex toy control library

feat: Add support for ActiveJoy Vibrating egg

authored by blackspherefollower and committed by qDot eaeed814 d4be80ac

+151 -1
+34
buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json
··· 12696 } 12697 } 12698 ] 12699 } 12700 } 12701 }
··· 12696 } 12697 } 12698 ] 12699 + }, 12700 + "activejoy": { 12701 + "defaults": { 12702 + "name": "IntoYou Remote Egg Vibrator", 12703 + "features": [ 12704 + { 12705 + "feature-type": "Vibrate", 12706 + "actuator": { 12707 + "step-range": [ 12708 + 0, 12709 + 255 12710 + ], 12711 + "messages": [ 12712 + "ScalarCmd" 12713 + ] 12714 + } 12715 + } 12716 + ] 12717 + }, 12718 + "communication": [ 12719 + { 12720 + "btle": { 12721 + "names": [ 12722 + "SS-TD-YDTD-001" 12723 + ], 12724 + "services": { 12725 + "0000f0b0-0000-1000-8000-00805f9b34fb": { 12726 + "tx": "0000f0b1-0000-1000-8000-00805f9b34fb", 12727 + "rx": "0000f0b2-0000-1000-8000-00805f9b34fb" 12728 + } 12729 + } 12730 + } 12731 + } 12732 + ] 12733 } 12734 } 12735 }
+19
buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml
··· 7269 tx: d973f2f4-b19e-11e2-9e96-0800200c9a66 7270 d973f2e5-b19e-11e2-9e96-0800200c9a66: 7271 rx: d973f2e6-b19e-11e2-9e96-0800200c9a66
··· 7269 tx: d973f2f4-b19e-11e2-9e96-0800200c9a66 7270 d973f2e5-b19e-11e2-9e96-0800200c9a66: 7271 rx: d973f2e6-b19e-11e2-9e96-0800200c9a66 7272 + activejoy: 7273 + defaults: 7274 + name: IntoYou Remote Egg Vibrator 7275 + features: 7276 + - feature-type: Vibrate 7277 + actuator: 7278 + step-range: 7279 + - 0 7280 + - 255 7281 + messages: 7282 + - ScalarCmd 7283 + communication: 7284 + - btle: 7285 + names: 7286 + - SS-TD-YDTD-001 7287 + services: 7288 + 0000f0b0-0000-1000-8000-00805f9b34fb: 7289 + tx: 0000f0b1-0000-1000-8000-00805f9b34fb 7290 + rx: 0000f0b2-0000-1000-8000-00805f9b34fb
+1 -1
buttplug/buttplug-device-config/package.json
··· 4 "description": "Buttplug Device Configuration File", 5 "main": "index.js", 6 "scripts": { 7 - "build": "js-yaml device-config-v2/buttplug-device-config-v2.yml > build-config/buttplug-device-config-v2.json && ajv validate --strict=false -s device-config-v2/buttplug-device-config-schema.json -d build-config/buttplug-device-config.json", 8 "build:v3": "js-yaml device-config-v3/buttplug-device-config-v3.yml > build-config/buttplug-device-config-v3.json && ajv validate --strict=false -s device-config-v3/buttplug-device-config-schema-v3.json -d build-config/buttplug-device-config-v3.json", 9 "convert": "node ./convert-v2-to-v3.js" 10 },
··· 4 "description": "Buttplug Device Configuration File", 5 "main": "index.js", 6 "scripts": { 7 + "build": "js-yaml device-config-v2/buttplug-device-config-v2.yml > build-config/buttplug-device-config-v2.json && ajv validate --strict=false -s device-config-v2/buttplug-device-config-schema-v2.json -d build-config/buttplug-device-config-v2.json", 8 "build:v3": "js-yaml device-config-v3/buttplug-device-config-v3.yml > build-config/buttplug-device-config-v3.json && ajv validate --strict=false -s device-config-v3/buttplug-device-config-schema-v3.json -d build-config/buttplug-device-config-v3.json", 9 "convert": "node ./convert-v2-to-v3.js" 10 },
+46
buttplug/src/server/device/protocol/activejoy.rs
···
··· 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 + 8 + use crate::{ 9 + core::{errors::ButtplugDeviceError, message::Endpoint}, 10 + server::device::{ 11 + hardware::{HardwareCommand, HardwareWriteCmd}, 12 + protocol::{generic_protocol_setup, ProtocolHandler}, 13 + }, 14 + }; 15 + 16 + generic_protocol_setup!(ActiveJoy, "activejoy"); 17 + 18 + #[derive(Default)] 19 + pub struct ActiveJoy {} 20 + 21 + impl ProtocolHandler for ActiveJoy { 22 + fn keepalive_strategy(&self) -> super::ProtocolKeepaliveStrategy { 23 + super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy 24 + } 25 + 26 + fn handle_scalar_vibrate_cmd( 27 + &self, 28 + index: u32, 29 + scalar: u32, 30 + ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 31 + Ok(vec![HardwareWriteCmd::new( 32 + Endpoint::Tx, 33 + [ 34 + 0xb0, // static header 35 + 0x01, // mode: 1=vibe, 5=shock, 6=thrust, 7=suction, 8=rotation, 16=swing, 36 + 0x00, // strong mode = 1 (thrust, suction, swing, rotate) 37 + index as u8, // 0 unless vibe2 38 + if scalar == 0 { 0x00 } else { 0x01 }, 39 + scalar as u8, 40 + ] 41 + .to_vec(), 42 + false, 43 + ) 44 + .into()]) 45 + } 46 + }
+5
buttplug/src/server/device/protocol/mod.rs
··· 13 pub mod fleshlight_launch_helper; 14 15 // Since users can pick and choose protocols, we need all of these to be public. 16 pub mod adrienlastic; 17 pub mod aneros; 18 pub mod ankni; ··· 197 map.insert(factory.identifier().to_owned(), factory); 198 } 199 200 add_to_protocol_map( 201 &mut map, 202 adrienlastic::setup::AdrienLasticIdentifierFactory::default(),
··· 13 pub mod fleshlight_launch_helper; 14 15 // Since users can pick and choose protocols, we need all of these to be public. 16 + pub mod activejoy; 17 pub mod adrienlastic; 18 pub mod aneros; 19 pub mod ankni; ··· 198 map.insert(factory.identifier().to_owned(), factory); 199 } 200 201 + add_to_protocol_map( 202 + &mut map, 203 + activejoy::setup::ActiveJoyIdentifierFactory::default(), 204 + ); 205 add_to_protocol_map( 206 &mut map, 207 adrienlastic::setup::AdrienLasticIdentifierFactory::default(),
+4
buttplug/tests/test_device_protocols.rs
··· 102 #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] 103 #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] 104 #[test_case("test_motorbunny_protocol.yaml" ; "Motorbunny Protocol")] 105 #[tokio::test] 106 async fn test_device_protocols_embedded_v3(test_file: &str) { 107 //tracing_subscriber::fmt::init(); ··· 193 #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] 194 #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] 195 #[test_case("test_motorbunny_protocol.yaml" ; "Motorbunny Protocol")] 196 #[tokio::test] 197 async fn test_device_protocols_json_v3(test_file: &str) { 198 //tracing_subscriber::fmt::init(); ··· 260 #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] 261 #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] 262 #[test_case("test_motorbunny_protocol.yaml" ; "Motorbunny Protocol")] 263 #[tokio::test] 264 async fn test_device_protocols_embedded_v2(test_file: &str) { 265 util::device_test::client::client_v2::run_embedded_test_case(&load_test_case(test_file).await) ··· 326 #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] 327 #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] 328 #[test_case("test_motorbunny_protocol.yaml" ; "Motorbunny Protocol")] 329 #[tokio::test] 330 async fn test_device_protocols_json_v2(test_file: &str) { 331 util::device_test::client::client_v2::run_json_test_case(&load_test_case(test_file).await).await;
··· 102 #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] 103 #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] 104 #[test_case("test_motorbunny_protocol.yaml" ; "Motorbunny Protocol")] 105 + #[test_case("test_activejoy_protocol.yaml" ; "ActiveJoy Protocol")] 106 #[tokio::test] 107 async fn test_device_protocols_embedded_v3(test_file: &str) { 108 //tracing_subscriber::fmt::init(); ··· 194 #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] 195 #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] 196 #[test_case("test_motorbunny_protocol.yaml" ; "Motorbunny Protocol")] 197 + #[test_case("test_activejoy_protocol.yaml" ; "ActiveJoy Protocol")] 198 #[tokio::test] 199 async fn test_device_protocols_json_v3(test_file: &str) { 200 //tracing_subscriber::fmt::init(); ··· 262 #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] 263 #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] 264 #[test_case("test_motorbunny_protocol.yaml" ; "Motorbunny Protocol")] 265 + #[test_case("test_activejoy_protocol.yaml" ; "ActiveJoy Protocol")] 266 #[tokio::test] 267 async fn test_device_protocols_embedded_v2(test_file: &str) { 268 util::device_test::client::client_v2::run_embedded_test_case(&load_test_case(test_file).await) ··· 329 #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] 330 #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] 331 #[test_case("test_motorbunny_protocol.yaml" ; "Motorbunny Protocol")] 332 + #[test_case("test_activejoy_protocol.yaml" ; "ActiveJoy Protocol")] 333 #[tokio::test] 334 async fn test_device_protocols_json_v2(test_file: &str) { 335 util::device_test::client::client_v2::run_json_test_case(&load_test_case(test_file).await).await;
+42
buttplug/tests/util/device_test/device_test_case/test_activejoy_protocol.yaml
···
··· 1 + devices: 2 + - identifier: 3 + name: "SS-TD-YDTD-001" 4 + expected_name: "IntoYou Remote Egg Vibrator" 5 + device_commands: 6 + - !Messages 7 + device_index: 0 8 + messages: 9 + - !Vibrate 10 + - Index: 0 11 + Speed: 0.5 12 + - !Commands 13 + device_index: 0 14 + commands: 15 + - !Write 16 + endpoint: tx 17 + data: [0xb0, 0x01, 0x00, 0x00, 0x01, 0x80] 18 + write_with_response: false 19 + - !Messages 20 + device_index: 0 21 + messages: 22 + - !Vibrate 23 + - Index: 0 24 + Speed: 0.75 25 + - !Commands 26 + device_index: 0 27 + commands: 28 + - !Write 29 + endpoint: tx 30 + data: [0xb0, 0x01, 0x00, 0x00, 0x01, 0xc0] 31 + write_with_response: false 32 + - !Messages 33 + device_index: 0 34 + messages: 35 + - !Stop 36 + - !Commands 37 + device_index: 0 38 + commands: 39 + - !Write 40 + endpoint: tx 41 + data: [0xb0, 0x01, 0x00, 0x00, 0x00, 0x00] 42 + write_with_response: false