From 641766e2ba33fea57b595d8e5987db89acc8e4bd Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Sat, 4 Jan 2025 16:03:56 +0000 Subject: [PATCH 01/22] feat: Adding support for Joyhub Vince Maynor and Dallin --- .../buttplug-device-config-v3.json | 102 +++++++++++++++++- .../buttplug-device-config-v3.yml | 58 ++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index cf886382d..7d800bdbc 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -16524,6 +16524,103 @@ } } ] + }, + { + "identifier": [ + "J-Vince" + ], + "name": "JoyHub Vince", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + { + "identifier": [ + "J-Dallin" + ], + "name": "JoyHub Dallin", + "features": [ + { + "feature-type": "Oscillate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + { + "identifier": [ + "J-Mace2" + ], + "name": "JoyHub Maynor", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Constrict", + "description": "Air Pump", + "actuator": { + "step-range": [ + 0, + 9 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] } ], "communication": [ @@ -16571,7 +16668,10 @@ "J-Pau", "J-Petalwish3", "J-Marshal", - "J-Piet2" + "J-Piet2", + "J-Vince", + "J-Dallin", + "J-Mace2" ], "services": { "0000ffa0-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 571dd402c..6fc29f412 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -9451,6 +9451,61 @@ protocols: - 9 messages: - ScalarCmd + - identifier: + - J-Vince + name: JoyHub Vince + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - identifier: + - J-Dallin + name: JoyHub Dallin + features: + - feature-type: Oscillate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - identifier: + - J-Mace2 + name: JoyHub Maynor + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Constrict + description: Air Pump + actuator: + step-range: + - 0 + - 9 + messages: + - ScalarCmd communication: - btle: names: @@ -9496,6 +9551,9 @@ protocols: - J-Petalwish3 - J-Marshal - J-Piet2 + - J-Vince + - J-Dallin + - J-Mace2 services: 0000ffa0-0000-1000-8000-00805f9b34fb: tx: 0000ffa1-0000-1000-8000-00805f9b34fb From 41f1e9192c217d97970af822d16177a1ad8797bf Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Sat, 4 Jan 2025 16:04:42 +0000 Subject: [PATCH 02/22] chore: Bump config version --- .../build-config/buttplug-device-config-v3.json | 2 +- .../device-config-v3/buttplug-device-config-v3.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 7d800bdbc..778d00566 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -1,7 +1,7 @@ { "version": { "major": 3, - "minor": 10 + "minor": 11 }, "protocols": { "lovense": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 6fc29f412..c1270313c 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -1,6 +1,6 @@ version: major: 3 - minor: 10 + minor: 11 protocols: lovense: defaults: From 7447066ebc83cc8bca940b0f5f09f779d41fa13b Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Sun, 5 Jan 2025 13:15:20 +0000 Subject: [PATCH 03/22] feat: Adding support for Svakom Emma Neo 2 and Mini Emma Neo --- .../buttplug-device-config-v3.json | 32 +++++++++++++++++-- .../buttplug-device-config-v3.yml | 16 ++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 778d00566..d6c0f37f9 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -5413,6 +5413,12 @@ "Cici 2" ], "name": "Svakom Cici 2" + }, + { + "identifier": [ + "Emma Neo 2" + ], + "name": "Svakom Emma Neo 2" } ], "communication": [ @@ -5430,7 +5436,8 @@ "Vick Neo", "STG05A", "QH-SJ007A", - "Cici 2" + "Cici 2", + "Emma Neo 2" ], "services": { "0000ffe0-0000-1000-8000-00805f9b34fb": { @@ -5751,6 +5758,26 @@ } } ] + }, + { + "identifier": [ + "Mini Emma Neo" + ], + "name": "Svakom Mini Emma Neo", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 10 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] } ], "communication": [ @@ -5759,7 +5786,8 @@ "names": [ "Chika", "Mora Neo", - "Trysta Neo" + "Trysta Neo", + "Mini Emma Neo" ], "services": { "0000ffe0-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index c1270313c..64c9722c5 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -3085,6 +3085,9 @@ protocols: - identifier: - Cici 2 name: Svakom Cici 2 + - identifier: + - Emma Neo 2 + name: Svakom Emma Neo 2 communication: - btle: names: @@ -3100,6 +3103,7 @@ protocols: - STG05A - QH-SJ007A - Cici 2 + - Emma Neo 2 services: 0000ffe0-0000-1000-8000-00805f9b34fb: tx: 0000ffe1-0000-1000-8000-00805f9b34fb @@ -3281,12 +3285,24 @@ protocols: - 3 messages: - ScalarCmd + - identifier: + - Mini Emma Neo + name: Svakom Mini Emma Neo + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 10 + messages: + - ScalarCmd communication: - btle: names: - Chika - Mora Neo - Trysta Neo + - Mini Emma Neo services: 0000ffe0-0000-1000-8000-00805f9b34fb: tx: 0000ffe1-0000-1000-8000-00805f9b34fb From 46a138e39926808be04b522e918f14936f025c07 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Sun, 5 Jan 2025 19:23:47 +0000 Subject: [PATCH 04/22] feat: Adding support for metaXsire Zeus --- .../buttplug-device-config-v3.json | 35 ++++++- .../buttplug-device-config-v3.yml | 19 ++++ .../server/device/protocol/metaxsire_v3.rs | 98 ++++++++++++------- 3 files changed, 113 insertions(+), 39 deletions(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index d6c0f37f9..d43f14cc9 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -11075,6 +11075,38 @@ "TAY009" ], "name": "metaXsire Tay 9" + }, + { + "identifier": [ + "TA-S001A" + ], + "name": "metaXsire Zeus", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 20 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Oscillate", + "actuator": { + "step-range": [ + 0, + 20 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] } ], "communication": [ @@ -11082,7 +11114,8 @@ "btle": { "names": [ "TAY001", - "TAY009" + "TAY009", + "TA-S001A" ], "services": { "0000fff0-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 64c9722c5..7325e562e 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -6307,11 +6307,30 @@ protocols: - identifier: - TAY009 name: metaXsire Tay 9 + - identifier: + - TA-S001A + name: metaXsire Zeus + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 20 + messages: + - ScalarCmd + - feature-type: Oscillate + actuator: + step-range: + - 0 + - 20 + messages: + - ScalarCmd communication: - btle: names: - TAY001 - TAY009 + - TA-S001A services: 0000fff0-0000-1000-8000-00805f9b34fb: tx: 0000fe02-0000-1000-8000-00805f9b34fb diff --git a/buttplug/src/server/device/protocol/metaxsire_v3.rs b/buttplug/src/server/device/protocol/metaxsire_v3.rs index f309b25a2..c27ac03c9 100644 --- a/buttplug/src/server/device/protocol/metaxsire_v3.rs +++ b/buttplug/src/server/device/protocol/metaxsire_v3.rs @@ -5,6 +5,7 @@ // Licensed under the BSD 3-Clause license. See LICENSE file in the project root // for full license information. +use crate::core::message::ActuatorType; use crate::{ core::{errors::ButtplugDeviceError, message::Endpoint}, server::device::{ @@ -20,11 +21,9 @@ use crate::{ util::{async_manager, sleep}, }; use async_trait::async_trait; -use std::sync::{ - atomic::{AtomicU8, Ordering}, - Arc, -}; +use std::sync::Arc; use std::time::Duration; +use tokio::sync::RwLock; generic_protocol_initializer_setup!(MetaXSireV3, "metaxsire-v3"); #[derive(Default)] @@ -35,46 +34,59 @@ impl ProtocolInitializer for MetaXSireV3Initializer { async fn initialize( &mut self, hardware: Arc, - _: &UserDeviceDefinition, + device_definition: &UserDeviceDefinition, ) -> Result, ButtplugDeviceError> { - Ok(Arc::new(MetaXSireV3::new(hardware))) + let feature_count = device_definition + .features() + .iter() + .filter(|x| x.actuator().is_some()) + .count(); + Ok(Arc::new(MetaXSireV3::new(hardware, feature_count))) } } const METAXSIRE_COMMAND_DELAY_MS: u64 = 100; -async fn command_update_handler(device: Arc, command_holder: Arc) { +async fn command_update_handler(device: Arc, command_holder: Arc>>) { trace!("Entering metaXsire v3 Control Loop"); - let mut current_command = command_holder.load(Ordering::Relaxed); - while current_command == 0 - || device - .write_value(&HardwareWriteCmd::new( - Endpoint::Tx, - vec![0xa1, 0x04, current_command, 0x01], - false, - )) - .await - .is_ok() - { + let mut current_commands = command_holder.read().await.clone(); + let mut errored = false; + while !errored { + for i in 0..current_commands.len() { + if current_commands[i] == 0 { + continue; + } + errored = !device + .write_value(&HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa1, 0x04, current_commands[i], i as u8 + 1], + false, + )) + .await + .is_ok(); + if errored { + break; + } + } sleep(Duration::from_millis(METAXSIRE_COMMAND_DELAY_MS)).await; - current_command = command_holder.load(Ordering::Relaxed); - trace!("metaXsire v3 Command: {:?}", current_command); + current_commands = command_holder.read().await.clone(); + trace!("metaXsire v3 Command: {:?}", current_commands); } trace!("metaXsire v3 control loop exiting, most likely due to device disconnection."); } pub struct MetaXSireV3 { - current_command: Arc, + current_commands: Arc>>, } impl MetaXSireV3 { - fn new(device: Arc) -> Self { - let current_command = Arc::new(AtomicU8::new(0)); - let current_command_clone = current_command.clone(); + fn new(device: Arc, feature_count: usize) -> Self { + let current_commands = Arc::new(RwLock::new(vec![0u8; feature_count])); + let current_commands_clone = current_commands.clone(); async_manager::spawn( - async move { command_update_handler(device, current_command_clone).await }, + async move { command_update_handler(device, current_commands_clone).await }, ); - Self { current_command } + Self { current_commands } } } @@ -83,19 +95,29 @@ impl ProtocolHandler for MetaXSireV3 { super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy } - fn handle_scalar_vibrate_cmd( + fn handle_scalar_cmd( &self, - _index: u32, - scalar: u32, + commands: &[Option<(ActuatorType, u32)>], ) -> Result, ButtplugDeviceError> { - let current_command = self.current_command.clone(); - current_command.store(scalar as u8, Ordering::Relaxed); - - Ok(vec![HardwareWriteCmd::new( - Endpoint::Tx, - vec![0xa1, 0x04, scalar as u8, 0x01], - true, - ) - .into()]) + let mut cmds = vec![]; + for i in 0..commands.len() { + if let Some(cmd) = commands[i] { + let current_commands = self.current_commands.clone(); + async_manager::spawn(async move { + let write_mutex = current_commands.clone(); + let mut command_writer = write_mutex.write().await; + command_writer[i] = cmd.1 as u8; + }); + cmds.push( + HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa1, 0x04, cmd.1 as u8, i as u8 + 1], + true, + ) + .into(), + ); + } + } + Ok(cmds) } } From e265fd64d49403ff2e2c38d049b2319650df60c1 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Sun, 5 Jan 2025 19:49:24 +0000 Subject: [PATCH 05/22] feat: Adding support for Tracy's Dog Craybit Pro --- .../buttplug-device-config-v3.json | 47 ++++++++++++++++++- .../buttplug-device-config-v3.yml | 26 ++++++++++ .../src/server/device/protocol/monsterpub.rs | 7 ++- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index d43f14cc9..92c1e1906 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -14532,6 +14532,50 @@ } } ] + }, + { + "identifier": [ + "TDG_CRAYBIT_PT" + ], + "name": "Tracy's Dog Craybit Pro", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] } ], "communication": [ @@ -14546,7 +14590,8 @@ "00006000-0000-1000-8000-00805f9b34fb": { "tx": "00006001-0000-1000-8000-00805f9b34fb", "txmode": "00006002-0000-1000-8000-00805f9b34fb", - "txvibrate": "00006003-0000-1000-8000-00805f9b34fb" + "txvibrate": "00006003-0000-1000-8000-00805f9b34fb", + "generic0": "0000600a-0000-1000-8000-00805f9b34fb" }, "00006010-0000-1000-8000-00805f9b34fb": { "rxblemodel": "00006014-0000-1000-8000-00805f9b34fb" diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 7325e562e..603739830 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -8310,6 +8310,31 @@ protocols: - 100 messages: - ScalarCmd + - identifier: + - TDG_CRAYBIT_PT + name: Tracy's Dog Craybit Pro + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd communication: - btle: names: @@ -8321,6 +8346,7 @@ protocols: tx: 00006001-0000-1000-8000-00805f9b34fb txmode: 00006002-0000-1000-8000-00805f9b34fb txvibrate: 00006003-0000-1000-8000-00805f9b34fb + generic0: 0000600a-0000-1000-8000-00805f9b34fb 00006010-0000-1000-8000-00805f9b34fb: rxblemodel: 00006014-0000-1000-8000-00805f9b34fb 00008000-0000-1000-8000-00805f9b34fb: diff --git a/buttplug/src/server/device/protocol/monsterpub.rs b/buttplug/src/server/device/protocol/monsterpub.rs index c183259a2..0a949ed66 100644 --- a/buttplug/src/server/device/protocol/monsterpub.rs +++ b/buttplug/src/server/device/protocol/monsterpub.rs @@ -117,8 +117,10 @@ impl ProtocolInitializer for MonsterPubInitializer { Ok(Arc::new(MonsterPub::new( if hardware.endpoints().contains(&Endpoint::TxVibrate) { Endpoint::TxVibrate - } else { + } else if hardware.endpoints().contains(&Endpoint::Tx) { Endpoint::Tx + } else { + Endpoint::Generic0 // tracy's dog 3 vibe }, ))) } @@ -149,6 +151,9 @@ impl ProtocolHandler for MonsterPub { ) -> Result, ButtplugDeviceError> { let mut data = vec![]; let mut stop = true; + if self.tx == Endpoint::Generic0 { + data.push(3u8); + } for (_, cmd) in cmds.iter().enumerate() { if let Some((_, speed)) = cmd { data.push(*speed as u8); From 1f7cbe81597bcd77e44bbfa2847c9fcbd8c19541 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 7 Jan 2025 15:59:47 +0000 Subject: [PATCH 06/22] feat: Adding support for Nexus Revo Stealth --- .../buttplug-device-config-v3.json | 45 ++++++++++++++ .../buttplug-device-config-v3.yml | 25 ++++++++ buttplug/src/server/device/protocol/mod.rs | 5 ++ .../src/server/device/protocol/nexus_revo.rs | 60 ++++++++++++++++++ buttplug/tests/test_device_protocols.rs | 4 ++ .../device_test_case/test_nexus_revo.yaml | 62 +++++++++++++++++++ 6 files changed, 201 insertions(+) create mode 100644 buttplug/src/server/device/protocol/nexus_revo.rs create mode 100644 buttplug/tests/util/device_test/device_test_case/test_nexus_revo.yaml diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 92c1e1906..96cf8941f 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -17696,6 +17696,51 @@ } } ] + }, + "nexus-revo": { + "defaults": { + "name": "Nexus Revo Stealth", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 10 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Rotate", + "actuator": { + "step-range": [ + 0, + 2 + ], + "messages": [ + "RotateCmd" + ] + } + } + ] + }, + "communication": [ + { + "btle": { + "names": [ + "XW-LW3" + ], + "services": { + "0000c570-0000-1000-8000-00805f9b34fb": { + "tx": "0000c571-0000-1000-8000-00805f9b34fb" + } + } + } + } + ] } } } diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 603739830..1ab498844 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -10136,3 +10136,28 @@ protocols: services: 0000ffe0-0000-1000-8000-00805f9b34fb: tx: 0000ffe1-0000-1000-8000-00805f9b34fb + nexus-revo: + defaults: + name: Nexus Revo Stealth + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 10 + messages: + - ScalarCmd + - feature-type: Rotate + actuator: + step-range: + - 0 + - 2 + messages: + - RotateCmd + communication: + - btle: + names: + - XW-LW3 + services: + 0000c570-0000-1000-8000-00805f9b34fb: + tx: 0000c571-0000-1000-8000-00805f9b34fb diff --git a/buttplug/src/server/device/protocol/mod.rs b/buttplug/src/server/device/protocol/mod.rs index c714dea77..8b6b38e12 100644 --- a/buttplug/src/server/device/protocol/mod.rs +++ b/buttplug/src/server/device/protocol/mod.rs @@ -84,6 +84,7 @@ pub mod motorbunny; pub mod mysteryvibe; pub mod mysteryvibe_v2; pub mod nextlevelracing; +pub mod nexus_revo; pub mod nintendo_joycon; pub mod nobra; pub mod patoo; @@ -454,6 +455,10 @@ pub fn get_default_protocol_map() -> HashMap super::ProtocolKeepaliveStrategy { + super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy + } + + fn handle_scalar_vibrate_cmd( + &self, + _index: u32, + scalar: u32, + ) -> Result, ButtplugDeviceError> { + Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xaa, 0x01, 0x01, 0x00, 0x01, scalar as u8], + true, + ) + .into()]) + } + + fn handle_rotate_cmd( + &self, + commands: &[Option<(u32, bool)>], + ) -> Result, ButtplugDeviceError> { + if let Some(Some(cmd)) = commands.first() { + return Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![ + 0xaa, + 0x01, + 0x02, + 0x00, + cmd.0 as u8 + if cmd.0 != 0 && cmd.1 { 2 } else { 0 }, + 0x00, + ], + true, + ) + .into()]); + } + Ok(vec![]) + } +} diff --git a/buttplug/tests/test_device_protocols.rs b/buttplug/tests/test_device_protocols.rs index 9c7a92e82..d42896593 100644 --- a/buttplug/tests/test_device_protocols.rs +++ b/buttplug/tests/test_device_protocols.rs @@ -119,6 +119,7 @@ async fn load_test_case(test_file: &str) -> DeviceTestCase { #[test_case("test_serveu_protocol.yaml" ; "ServeU")] #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] +#[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[tokio::test] async fn test_device_protocols_embedded_v3(test_file: &str) { //tracing_subscriber::fmt::init(); @@ -228,6 +229,7 @@ async fn test_device_protocols_embedded_v3(test_file: &str) { #[test_case("test_serveu_protocol.yaml" ; "ServeU")] #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] +#[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[tokio::test] async fn test_device_protocols_json_v3(test_file: &str) { //tracing_subscriber::fmt::init(); @@ -307,6 +309,7 @@ async fn test_device_protocols_json_v3(test_file: &str) { #[test_case("test_serveu_protocol.yaml" ; "ServeU")] #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] +#[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[tokio::test] async fn test_device_protocols_embedded_v2(test_file: &str) { util::device_test::client::client_v2::run_embedded_test_case(&load_test_case(test_file).await) @@ -385,6 +388,7 @@ async fn test_device_protocols_embedded_v2(test_file: &str) { #[test_case("test_serveu_protocol.yaml" ; "ServeU")] #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] +#[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[tokio::test] async fn test_device_protocols_json_v2(test_file: &str) { util::device_test::client::client_v2::run_json_test_case(&load_test_case(test_file).await).await; diff --git a/buttplug/tests/util/device_test/device_test_case/test_nexus_revo.yaml b/buttplug/tests/util/device_test/device_test_case/test_nexus_revo.yaml new file mode 100644 index 000000000..f98dad7c5 --- /dev/null +++ b/buttplug/tests/util/device_test/device_test_case/test_nexus_revo.yaml @@ -0,0 +1,62 @@ +devices: + - identifier: + name: "XW-LW3" + expected_name: "Nexus Revo Stealth" +device_commands: + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 0.5 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + # "Vibrate:10;" + data: [0xaa, 0x01, 0x01, 0x00, 0x01, 0x05] + write_with_response: true + - !Messages + device_index: 0 + messages: + - !Rotate + - Index: 0 + Speed: 0.5 + Clockwise: true + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xaa, 0x01, 0x02, 0x00, 0x03, 0x00] + write_with_response: true + - !Messages + device_index: 0 + messages: + - !Rotate + - Index: 0 + Speed: 1.0 + Clockwise: false + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xaa, 0x01, 0x02, 0x00, 0x02, 0x00] + write_with_response: true + - !Messages + device_index: 0 + messages: + - !Stop + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xaa, 0x01, 0x01, 0x00, 0x01, 0x00] + write_with_response: true + - !Write + endpoint: tx + data: [0xaa, 0x01, 0x02, 0x00, 0x00, 0x00] + write_with_response: true From 02d1ba895c323d87b121e795395d46a4c2fd4627 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 7 Jan 2025 16:00:05 +0000 Subject: [PATCH 07/22] chore: cargo fmt --- .../server/device/protocol/kiiroo_prowand.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/buttplug/src/server/device/protocol/kiiroo_prowand.rs b/buttplug/src/server/device/protocol/kiiroo_prowand.rs index 1a66dbfb1..65f46d4fe 100644 --- a/buttplug/src/server/device/protocol/kiiroo_prowand.rs +++ b/buttplug/src/server/device/protocol/kiiroo_prowand.rs @@ -8,26 +8,15 @@ use crate::{ core::{ errors::ButtplugDeviceError, - message::{ - self, - ButtplugDeviceMessage, - Endpoint, - SensorReadingV4, - }, + message::{self, ButtplugDeviceMessage, Endpoint, SensorReadingV4}, }, server::device::{ hardware::{Hardware, HardwareCommand, HardwareReadCmd, HardwareWriteCmd}, protocol::{generic_protocol_setup, ProtocolHandler}, }, }; -use futures::{ - future::BoxFuture, - FutureExt, -}; -use std::{ - default::Default, - sync::Arc, -}; +use futures::{future::BoxFuture, FutureExt}; +use std::{default::Default, sync::Arc}; generic_protocol_setup!(KiirooProWand, "kiiroo-prowand"); From 98258785b6edf81e01fbccd550c3127eadd9626d Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 7 Jan 2025 16:00:59 +0000 Subject: [PATCH 08/22] feat: Adding reported new PrettyLove device identifier --- .../build-config/buttplug-device-config-v3.json | 3 ++- .../device-config-v3/buttplug-device-config-v3.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 96cf8941f..4795cec2b 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -5264,7 +5264,8 @@ { "btle": { "names": [ - "Aogu BLE *" + "Aogu BLE *", + "AB Shutter3 [Aogu BLE Device]" ], "services": { "0000ffe5-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 1ab498844..ccef2a062 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -3005,6 +3005,7 @@ protocols: - btle: names: - Aogu BLE * + - AB Shutter3 [Aogu BLE Device] services: 0000ffe5-0000-1000-8000-00805f9b34fb: tx: 0000ffe9-0000-1000-8000-00805f9b34fb From a751355d643ca020982101cae40d4579e28cedb3 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Wed, 8 Jan 2025 11:00:44 +0000 Subject: [PATCH 09/22] feat: Adding support for Luvmazer Finger Magic --- .../buttplug-device-config-v3.json | 45 ++++++ .../buttplug-device-config-v3.yml | 25 ++++ .../src/server/device/protocol/luvmazer.rs | 139 ++++++++++++++++++ buttplug/src/server/device/protocol/mod.rs | 5 + buttplug/tests/test_device_protocols.rs | 2 + .../test_luvmazer_protocol.yaml | 55 +++++++ 6 files changed, 271 insertions(+) create mode 100644 buttplug/src/server/device/protocol/luvmazer.rs create mode 100644 buttplug/tests/util/device_test/device_test_case/test_luvmazer_protocol.yaml diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 4795cec2b..5bdc7608d 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -17742,6 +17742,51 @@ } } ] + }, + "luvmazer": { + "defaults": { + "name": "Luvmazer Finger Magic", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Rotate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + "communication": [ + { + "btle": { + "names": [ + "TKLM-W001-BT" + ], + "services": { + "0000ffa0-0000-1000-8000-00805f9b34fb": { + "tx": "0000ffa1-0000-1000-8000-00805f9b34fb" + } + } + } + } + ] } } } diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index ccef2a062..77ebe4d14 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -10162,3 +10162,28 @@ protocols: services: 0000c570-0000-1000-8000-00805f9b34fb: tx: 0000c571-0000-1000-8000-00805f9b34fb + luvmazer: + defaults: + name: Luvmazer Finger Magic + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Rotate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + communication: + - btle: + names: + - TKLM-W001-BT + services: + 0000ffa0-0000-1000-8000-00805f9b34fb: + tx: 0000ffa1-0000-1000-8000-00805f9b34fb diff --git a/buttplug/src/server/device/protocol/luvmazer.rs b/buttplug/src/server/device/protocol/luvmazer.rs new file mode 100644 index 000000000..7f09abc4e --- /dev/null +++ b/buttplug/src/server/device/protocol/luvmazer.rs @@ -0,0 +1,139 @@ +// Buttplug Rust Source Code File - See https://buttplug.io for more info. +// +// Copyright 2016-2025 Nonpolynomial Labs LLC. All rights reserved. +// +// Licensed under the BSD 3-Clause license. See LICENSE file in the project root +// for full license information. + +use crate::{ + core::{ + errors::ButtplugDeviceError, + message::{ActuatorType, Endpoint}, + }, + server::device::{ + configuration::UserDeviceDefinition, + hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, + protocol::{ + generic_protocol_initializer_setup, + ProtocolCommunicationSpecifier, + ProtocolHandler, + ProtocolIdentifier, + ProtocolInitializer, + UserDeviceIdentifier, + }, + }, + util::async_manager, +}; +use async_trait::async_trait; +use std::{sync::Arc, time::Duration}; +use tokio::time::sleep; + +generic_protocol_initializer_setup!(Luvmazer, "luvmazer"); + +async fn delayed_rotate_handler(device: Arc, scalar: u8) { + sleep(Duration::from_millis(25)).await; + let res = device + .write_value(&HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa0, 0x0f, 0x00, 0x00, 0x64, scalar as u8], + false, + )) + .await; + if res.is_err() { + error!("Delayed Luvmazer Rotate command error: {:?}", res.err()); + } +} +#[derive(Default)] +pub struct LuvmazerInitializer {} + +#[async_trait] +impl ProtocolInitializer for LuvmazerInitializer { + async fn initialize( + &mut self, + hardware: Arc, + _: &UserDeviceDefinition, + ) -> Result, ButtplugDeviceError> { + Ok(Arc::new(Luvmazer::new(hardware))) + } +} + +pub struct Luvmazer { + device: Arc, +} + +impl Luvmazer { + fn new(device: Arc) -> Self { + Self { device } + } +} + +impl ProtocolHandler for Luvmazer { + fn keepalive_strategy(&self) -> super::ProtocolKeepaliveStrategy { + super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy + } + + fn handle_scalar_vibrate_cmd( + &self, + _index: u32, + scalar: u32, + ) -> Result, ButtplugDeviceError> { + Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa0, 0x01, 0x00, 0x00, 0x64, scalar as u8], + false, + ) + .into()]) + } + + fn handle_scalar_rotate_cmd( + &self, + _index: u32, + scalar: u32, + ) -> Result, ButtplugDeviceError> { + Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa0, 0x0f, 0x00, 0x00, 0x64, scalar as u8], + false, + ) + .into()]) + } + + fn handle_scalar_cmd( + &self, + commands: &[Option<(ActuatorType, u32)>], + ) -> Result, ButtplugDeviceError> { + let cmd1 = commands[0]; + let cmd2 = if commands.len() > 1 { + commands[1] + } else { + None + }; + + if let Some(cmd) = cmd2 { + if cmd.0 == ActuatorType::Rotate { + if cmd1.is_some() { + let dev = self.device.clone(); + async_manager::spawn(async move { delayed_rotate_handler(dev, cmd.1 as u8).await }); + } else { + return Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa0, 0x0f, 0x00, 0x00, 0x64, cmd.1 as u8], + false, + ) + .into()]); + } + } + } + + if let Some(cmd) = cmd1 { + return Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa0, 0x01, 0x00, 0x00, 0x64, cmd.1 as u8], + false, + ) + .into()]); + } + + Ok(vec![]) + } +} diff --git a/buttplug/src/server/device/protocol/mod.rs b/buttplug/src/server/device/protocol/mod.rs index 8b6b38e12..94112a637 100644 --- a/buttplug/src/server/device/protocol/mod.rs +++ b/buttplug/src/server/device/protocol/mod.rs @@ -64,6 +64,7 @@ pub mod lovehoney_desire; pub mod lovense; pub mod lovense_connect_service; pub mod lovenuts; +pub mod luvmazer; pub mod magic_motion_v1; pub mod magic_motion_v2; pub mod magic_motion_v3; @@ -388,6 +389,10 @@ pub fn get_default_protocol_map() -> HashMap DeviceTestCase { #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] +#[test_case("test_luvmazer_protocol.yaml" ; "Luvmazer Protocol")] #[tokio::test] async fn test_device_protocols_embedded_v3(test_file: &str) { //tracing_subscriber::fmt::init(); @@ -230,6 +231,7 @@ async fn test_device_protocols_embedded_v3(test_file: &str) { #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] +#[test_case("test_luvmazer_protocol.yaml" ; "Luvmazer Protocol")] #[tokio::test] async fn test_device_protocols_json_v3(test_file: &str) { //tracing_subscriber::fmt::init(); diff --git a/buttplug/tests/util/device_test/device_test_case/test_luvmazer_protocol.yaml b/buttplug/tests/util/device_test/device_test_case/test_luvmazer_protocol.yaml new file mode 100644 index 000000000..81a28f305 --- /dev/null +++ b/buttplug/tests/util/device_test/device_test_case/test_luvmazer_protocol.yaml @@ -0,0 +1,55 @@ +devices: + - identifier: + name: "TKLM-W001-BT" + expected_name: "Luvmazer Finger Magic" +device_commands: + # Commands + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 0.5 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa0, 0x01, 0x00, 0x00, 0x64, 0x80] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Scalar + - Index: 0 + Scalar: 0.1 + ActuatorType: Vibrate + - Index: 1 + Scalar: 0.5 + ActuatorType: Rotate + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa0, 0x01, 0x00, 0x00, 0x64, 0x1a] + write_with_response: false + - !Write + endpoint: tx + data: [0xa0, 0x0f, 0x00, 0x00, 0x64, 0x80] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Stop + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa0, 0x01, 0x00, 0x00, 0x64, 0x0] + write_with_response: false + - !Write + endpoint: tx + data: [0xa0, 0x0f, 0x00, 0x00, 0x64, 0x00] + write_with_response: false From 55a4ab3f6b695b5cf8a735f9b37c5a03c6f24ac7 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Thu, 9 Jan 2025 13:44:56 +0000 Subject: [PATCH 10/22] feat: Adding support for JoyHub Melody --- .../buttplug-device-config-v3.json | 54 +++++ .../buttplug-device-config-v3.yml | 30 +++ .../src/server/device/protocol/joyhub_v6.rs | 201 ++++++++++++++++++ buttplug/src/server/device/protocol/mod.rs | 5 + 4 files changed, 290 insertions(+) create mode 100644 buttplug/src/server/device/protocol/joyhub_v6.rs diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 5bdc7608d..71a24ad84 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -17038,6 +17038,60 @@ } ] }, + "joyhub-v6": { + "defaults": { + "name": "JoyHub Device", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Constrict", + "description": "Suction", + "actuator": { + "step-range": [ + 0, + 9 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + "configurations": [ + { + "identifier": [ + "J-Melody" + ], + "name": "JoyHub Melody" + } + ], + "communication": [ + { + "btle": { + "names": [ + "J-Melody" + ], + "services": { + "0000ffa0-0000-1000-8000-00805f9b34fb": { + "tx": "0000ffa1-0000-1000-8000-00805f9b34fb" + } + } + } + } + ] + }, "itoys": { "defaults": { "name": "iToys Seagull", diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 77ebe4d14..e6373b9bf 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -9760,6 +9760,36 @@ protocols: services: 0000ffa0-0000-1000-8000-00805f9b34fb: tx: 0000ffa1-0000-1000-8000-00805f9b34fb + joyhub-v6: + defaults: + name: JoyHub Device + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Constrict + description: Suction + actuator: + step-range: + - 0 + - 9 + messages: + - ScalarCmd + configurations: + - identifier: + - J-Melody + name: JoyHub Melody + communication: + - btle: + names: + - J-Melody + services: + 0000ffa0-0000-1000-8000-00805f9b34fb: + tx: 0000ffa1-0000-1000-8000-00805f9b34fb itoys: defaults: name: iToys Seagull diff --git a/buttplug/src/server/device/protocol/joyhub_v6.rs b/buttplug/src/server/device/protocol/joyhub_v6.rs new file mode 100644 index 000000000..6455190d3 --- /dev/null +++ b/buttplug/src/server/device/protocol/joyhub_v6.rs @@ -0,0 +1,201 @@ +// Buttplug Rust Source Code File - See https://buttplug.io for more info. +// +// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved. +// +// Licensed under the BSD 3-Clause license. See LICENSE file in the project root +// for full license information. + +use crate::server::device::configuration::ProtocolCommunicationSpecifier; +use crate::{ + core::{ + errors::ButtplugDeviceError, + message::{ActuatorType, Endpoint}, + }, + generic_protocol_initializer_setup, + server::device::{ + configuration::{UserDeviceDefinition, UserDeviceIdentifier}, + hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, + protocol::{ProtocolHandler, ProtocolIdentifier, ProtocolInitializer}, + }, + util::{async_manager, sleep}, +}; +use async_trait::async_trait; +use std::sync::{Arc, RwLock}; +use std::time::Duration; + +generic_protocol_initializer_setup!(JoyHubV6, "joyhub-v6"); + +async fn delayed_constrict_handler(device: Arc, scalar: u8) { + sleep(Duration::from_millis(50)).await; + let res = device + .write_value(&HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa0, 0x0d, 0x00, 0x00, scalar, 0xff], + false, + )) + .await; + if res.is_err() { + error!("Delayed JoyHub Constrict command error: {:?}", res.err()); + } +} + +fn vibes_changed( + old_commands_lock: &RwLock>>, + new_commands: &[Option<(ActuatorType, u32)>], + exclude: Vec, +) -> bool { + let old_commands = old_commands_lock.read().expect("locks should work"); + if old_commands.len() != new_commands.len() { + return true; + } + + for i in 0..old_commands.len() { + if exclude.contains(&i) { + continue; + } + if let Some(ocmd) = old_commands[i] { + if let Some(ncmd) = new_commands[i] { + if ocmd.1 != ncmd.1 { + return true; + } + } + } + } + false +} + +fn scalar_changed( + old_commands_lock: &RwLock>>, + new_commands: &[Option<(ActuatorType, u32)>], + index: usize, +) -> bool { + let old_commands = old_commands_lock.read().expect("locks should work"); + if old_commands.len() != new_commands.len() { + return true; + } + + if index < old_commands.len() { + if let Some(ocmd) = old_commands[index] { + if let Some(ncmd) = new_commands[index] { + if ocmd.1 != ncmd.1 { + return true; + } + } + } + } + false +} + +#[derive(Default)] +pub struct JoyHubV6Initializer {} + +#[async_trait] +impl ProtocolInitializer for JoyHubV6Initializer { + async fn initialize( + &mut self, + hardware: Arc, + _: &UserDeviceDefinition, + ) -> Result, ButtplugDeviceError> { + Ok(Arc::new(JoyHubV6::new(hardware))) + } +} + +pub struct JoyHubV6 { + device: Arc, + last_cmds: RwLock>>, +} + +impl JoyHubV6 { + fn new(device: Arc) -> Self { + let last_cmds = RwLock::new(vec![]); + Self { device, last_cmds } + } +} + +impl ProtocolHandler for JoyHubV6 { + fn keepalive_strategy(&self) -> super::ProtocolKeepaliveStrategy { + super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy + } + + fn needs_full_command_set(&self) -> bool { + true + } + + fn handle_scalar_cmd( + &self, + commands: &[Option<(ActuatorType, u32)>], + ) -> Result, ButtplugDeviceError> { + let cmd1 = commands[0]; + let mut cmd2 = if commands.len() > 1 { + commands[1] + } else { + None + }; + let mut cmd3 = if commands.len() > 2 { + commands[2] + } else { + None + }; + + if let Some(cmd) = cmd2 { + if cmd.0 == ActuatorType::Constrict { + cmd2 = None; + if !scalar_changed(&self.last_cmds, commands, 1usize) { + // no-op + } else if vibes_changed(&self.last_cmds, commands, vec![1usize]) { + let dev = self.device.clone(); + async_manager::spawn(async move { delayed_constrict_handler(dev, cmd.1 as u8).await }); + } else { + let mut command_writer = self.last_cmds.write().expect("Locks should work"); + *command_writer = commands.to_vec(); + + return Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa0, 0x0d, 0x00, 0x00, cmd.1 as u8, 0xff], + false, + ) + .into()]); + } + } + } + + if let Some(cmd) = cmd3 { + if cmd.0 == ActuatorType::Constrict { + cmd3 = None; + if !scalar_changed(&self.last_cmds, commands, 2usize) { + // no-op + } else if vibes_changed(&self.last_cmds, commands, vec![2usize]) { + let dev = self.device.clone(); + async_manager::spawn(async move { delayed_constrict_handler(dev, cmd.1 as u8).await }); + } else { + let mut command_writer = self.last_cmds.write().expect("Locks should work"); + *command_writer = commands.to_vec(); + + return Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa0, 0x0d, 0x00, 0x00, cmd.1 as u8, 0xff], + false, + ) + .into()]); + } + } + } + + let mut command_writer = self.last_cmds.write().expect("Locks should work"); + *command_writer = commands.to_vec(); + Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![ + 0xa0, + 0x03, + cmd2.unwrap_or((ActuatorType::Rotate, 0)).1 as u8, + cmd1.unwrap_or((ActuatorType::Vibrate, 0)).1 as u8, + cmd3.unwrap_or((ActuatorType::Oscillate, 0)).1 as u8, + 0x00, + 0xaa, + ], + false, + ) + .into()]) + } +} diff --git a/buttplug/src/server/device/protocol/mod.rs b/buttplug/src/server/device/protocol/mod.rs index 94112a637..22564d5ac 100644 --- a/buttplug/src/server/device/protocol/mod.rs +++ b/buttplug/src/server/device/protocol/mod.rs @@ -43,6 +43,7 @@ pub mod joyhub_v2; pub mod joyhub_v3; pub mod joyhub_v4; pub mod joyhub_v5; +pub mod joyhub_v6; pub mod kgoal_boost; pub mod kiiroo_prowand; pub mod kiiroo_v2; @@ -318,6 +319,10 @@ pub fn get_default_protocol_map() -> HashMap Date: Tue, 14 Jan 2025 11:21:43 +0000 Subject: [PATCH 11/22] feat: Support for JoyHub Pathfinder and Scarlett --- .../buttplug-device-config-v3.json | 42 ++++++++++++++++++- .../buttplug-device-config-v3.yml | 23 ++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 71a24ad84..c2f1424a1 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -14744,6 +14744,12 @@ ], "name": "JoyHub Eclipse" }, + { + "identifier": [ + "J-Scarlett" + ], + "name": "JoyHub Scarlett" + }, { "identifier": [ "J-Petalwish2" @@ -15105,7 +15111,8 @@ "J-Mackay", "J-Rowdy3", "J-Eclipse", - "J-DukeDazzle2" + "J-DukeDazzle2", + "J-Scarlett" ], "services": { "0000ffa0-0000-1000-8000-00805f9b34fb": { @@ -15599,6 +15606,38 @@ } ] }, + { + "identifier": [ + "J-Pathfinder" + ], + "name": "JoyHub Pathfinder", + "features": [ + { + "feature-type": "Oscillate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, { "identifier": [ "J-VibRipple" @@ -16746,6 +16785,7 @@ "J-Vbarbie3f", "J-CHERLY2c", "J-Pathfinder2", + "J-Pathfinder", "J-VibRipple", "J-Verax", "J-Verax2", diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index e6373b9bf..06f4dbe5b 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -8424,6 +8424,9 @@ protocols: - identifier: - J-Eclipse name: JoyHub Eclipse + - identifier: + - J-Scarlett + name: JoyHub Scarlett - identifier: - J-Petalwish2 name: JoyHub Petalwish 2 @@ -8644,6 +8647,7 @@ protocols: - J-Rowdy3 - J-Eclipse - J-DukeDazzle2 + - J-Scarlett services: 0000ffa0-0000-1000-8000-00805f9b34fb: tx: 0000ffa1-0000-1000-8000-00805f9b34fb @@ -8926,6 +8930,24 @@ protocols: - 255 messages: - ScalarCmd + - identifier: + - J-Pathfinder + name: JoyHub Pathfinder + features: + - feature-type: Oscillate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd - identifier: - J-VibRipple name: JoyHub Angela @@ -9583,6 +9605,7 @@ protocols: - J-Vbarbie3f - J-CHERLY2c - J-Pathfinder2 + - J-Pathfinder - J-VibRipple - J-Verax - J-Verax2 From 253937d9f8e5362325b781a69461211ae84cbd67 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 14 Jan 2025 12:01:23 +0000 Subject: [PATCH 12/22] feat: Adding support for the Fox M70-2 --- .../build-config/buttplug-device-config-v3.json | 3 ++- .../device-config-v3/buttplug-device-config-v3.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index c2f1424a1..7da55e2e2 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -13831,7 +13831,8 @@ "names": [ "FOX", "FOX M70 Pro", - "FoxM70Pro" + "FoxM70Pro", + "FOX M70-2" ], "services": { "0000ae00-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 06f4dbe5b..59b080009 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -7895,6 +7895,7 @@ protocols: - FOX - FOX M70 Pro - FoxM70Pro + - FOX M70-2 services: 0000ae00-0000-1000-8000-00805f9b34fb: tx: 0000ae01-0000-1000-8000-00805f9b34fb From a60f3cf56a3ee7a98a2c6ee8e2a7157531672d49 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 14 Jan 2025 14:04:52 +0000 Subject: [PATCH 13/22] feat: Adding support for 7 more JoyHub devices - JoyHub Verax 4 - JoyHub Palmyra - JoyHub Maiden - JoyHub Viele 3 - JoyHub Xylia - JoyHub Tarik - JoyHub Urica Guard 2 --- .../buttplug-device-config-v3.json | 195 +++++++++++++++++- .../buttplug-device-config-v3.yml | 110 ++++++++++ 2 files changed, 303 insertions(+), 2 deletions(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 7da55e2e2..372bbc249 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -14751,6 +14751,18 @@ ], "name": "JoyHub Scarlett" }, + { + "identifier": [ + "J-Tarik" + ], + "name": "JoyHub Tarik" + }, + { + "identifier": [ + "J-UricaGuard2" + ], + "name": "JoyHub Urica Guard 2" + }, { "identifier": [ "J-Petalwish2" @@ -15113,7 +15125,9 @@ "J-Rowdy3", "J-Eclipse", "J-DukeDazzle2", - "J-Scarlett" + "J-Scarlett", + "J-Tarik", + "J-UricaGuard2" ], "services": { "0000ffa0-0000-1000-8000-00805f9b34fb": { @@ -16768,6 +16782,178 @@ } } ] + }, + { + "identifier": [ + "J-Verax4" + ], + "name": "JoyHub Verax 4", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + { + "identifier": [ + "J-Palmyra" + ], + "name": "JoyHub Palmyra", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Oscillate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + { + "identifier": [ + "J-Xylia" + ], + "name": "JoyHub Xylia", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Oscillate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + { + "identifier": [ + "J-Maiden" + ], + "name": "JoyHub Maiden", + "features": [ + { + "feature-type": "Rotate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Constrict", + "actuator": { + "step-range": [ + 0, + 5 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + { + "identifier": [ + "J-Viele3" + ], + "name": "JoyHub Viele 3", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Rotate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] } ], "communication": [ @@ -16819,7 +17005,12 @@ "J-Piet2", "J-Vince", "J-Dallin", - "J-Mace2" + "J-Mace2", + "J-Verax4", + "J-Palmyra", + "J-Maiden", + "J-Viele3", + "J-Xylia" ], "services": { "0000ffa0-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 59b080009..011a2e10f 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -8428,6 +8428,12 @@ protocols: - identifier: - J-Scarlett name: JoyHub Scarlett + - identifier: + - J-Tarik + name: JoyHub Tarik + - identifier: + - J-UricaGuard2 + name: JoyHub Urica Guard 2 - identifier: - J-Petalwish2 name: JoyHub Petalwish 2 @@ -8649,6 +8655,8 @@ protocols: - J-Eclipse - J-DukeDazzle2 - J-Scarlett + - J-Tarik + - J-UricaGuard2 services: 0000ffa0-0000-1000-8000-00805f9b34fb: tx: 0000ffa1-0000-1000-8000-00805f9b34fb @@ -9591,6 +9599,103 @@ protocols: - 9 messages: - ScalarCmd + - identifier: + - J-Verax4 + name: JoyHub Verax 4 + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - identifier: + - J-Palmyra + name: JoyHub Palmyra + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Oscillate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - identifier: + - J-Xylia + name: JoyHub Xylia + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Oscillate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - identifier: + - J-Maiden + name: JoyHub Maiden + features: + - feature-type: Rotate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Constrict + actuator: + step-range: + - 0 + - 5 + messages: + - ScalarCmd + - identifier: + - J-Viele3 + name: JoyHub Viele 3 + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Rotate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd communication: - btle: names: @@ -9640,6 +9745,11 @@ protocols: - J-Vince - J-Dallin - J-Mace2 + - J-Verax4 + - J-Palmyra + - J-Maiden + - J-Viele3 + - J-Xylia services: 0000ffa0-0000-1000-8000-00805f9b34fb: tx: 0000ffa1-0000-1000-8000-00805f9b34fb From 7caf6e5506d1cdc722cce14ca3dbcdf458bf8837 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 14 Jan 2025 14:54:03 +0000 Subject: [PATCH 14/22] feat: Adding service advertisement based Lovense matching This was tested with a renamed Gemini - I'm not sure if it's the complete list. --- .../buttplug-device-config-v3.json | 37 +++++++++++++++++++ .../buttplug-device-config-v3.yml | 36 ++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 372bbc249..220e3161d 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -858,6 +858,43 @@ ] } ], + "advertised-services": [ + "6e400001-b5a3-f393-e0a9-e50e24dcca9e", + "50300001-0024-4bd4-bbd5-a6920e4c5653", + "57300001-0023-4bd4-bbd5-a6920e4c5653", + "5a300001-0024-4bd4-bbd5-a6920e4c5653", + "50300001-0023-4bd4-bbd5-a6920e4c5653", + "53300001-0023-4bd4-bbd5-a6920e4c5653", + "5a300001-0023-4bd4-bbd5-a6920e4c5653", + "4f300001-0023-4bd4-bbd5-a6920e4c5653", + "42300001-0023-4bd4-bbd5-a6920e4c5653", + "43300001-0023-4bd4-bbd5-a6920e4c5653", + "4c300001-0023-4bd4-bbd5-a6920e4c5653", + "4c410001-0023-4bd4-bbd5-a6920e4c5653", + "56300001-0023-4bd4-bbd5-a6920e4c5653", + "58300001-0023-4bd4-bbd5-a6920e4c5653", + "52300001-0023-4bd4-bbd5-a6920e4c5653", + "46300001-0023-4bd4-bbd5-a6920e4c5653", + "50300011-0023-4bd4-bbd5-a6920e4c5653", + "4a300001-0023-4bd4-bbd5-a6920e4c5653", + "45440001-0023-4bd4-bbd5-a6920e4c5653", + "45420001-0023-4bd4-bbd5-a6920e4c5653", + "54300001-0023-4bd4-bbd5-a6920e4c5653", + "45490001-0023-4bd4-bbd5-a6920e4c5653", + "4e300001-0023-4bd4-bbd5-a6920e4c5653", + "45410001-0023-4bd4-bbd5-a6920e4c5653", + "51300001-0023-4bd4-bbd5-a6920e4c5653", + "45460001-0023-4bd4-bbd5-a6920e4c5653", + "454c0001-0023-4bd4-bbd5-a6920e4c5653", + "55300001-0023-4bd4-bbd5-a6920e4c5653", + "53440001-0023-4bd4-bbd5-a6920e4c5653", + "48300001-0023-4bd4-bbd5-a6920e4c5653", + "46530001-0023-4bd4-bbd5-a6920e4c5653", + "42410001-0023-4bd4-bbd5-a6920e4c5653", + "43410001-0023-4bd4-bbd5-a6920e4c5653", + "4f430001-0023-4bd4-bbd5-a6920e4c5653", + "455a0001-0023-4bd4-bbd5-a6920e4c5653" + ], "services": { "0000fff0-0000-1000-8000-00805f9b34fb": { "tx": "0000fff2-0000-1000-8000-00805f9b34fb", diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 011a2e10f..86a9bf177 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -477,6 +477,42 @@ protocols: data: - 255 - 33 + advertised-services: + - 6e400001-b5a3-f393-e0a9-e50e24dcca9e + - 50300001-0024-4bd4-bbd5-a6920e4c5653 + - 57300001-0023-4bd4-bbd5-a6920e4c5653 + - 5a300001-0024-4bd4-bbd5-a6920e4c5653 + - 50300001-0023-4bd4-bbd5-a6920e4c5653 + - 53300001-0023-4bd4-bbd5-a6920e4c5653 + - 5a300001-0023-4bd4-bbd5-a6920e4c5653 + - 4f300001-0023-4bd4-bbd5-a6920e4c5653 + - 42300001-0023-4bd4-bbd5-a6920e4c5653 + - 43300001-0023-4bd4-bbd5-a6920e4c5653 + - 4c300001-0023-4bd4-bbd5-a6920e4c5653 + - 4c410001-0023-4bd4-bbd5-a6920e4c5653 + - 56300001-0023-4bd4-bbd5-a6920e4c5653 + - 58300001-0023-4bd4-bbd5-a6920e4c5653 + - 52300001-0023-4bd4-bbd5-a6920e4c5653 + - 46300001-0023-4bd4-bbd5-a6920e4c5653 + - 50300011-0023-4bd4-bbd5-a6920e4c5653 + - 4a300001-0023-4bd4-bbd5-a6920e4c5653 + - 45440001-0023-4bd4-bbd5-a6920e4c5653 + - 45420001-0023-4bd4-bbd5-a6920e4c5653 + - 54300001-0023-4bd4-bbd5-a6920e4c5653 + - 45490001-0023-4bd4-bbd5-a6920e4c5653 + - 4e300001-0023-4bd4-bbd5-a6920e4c5653 + - 45410001-0023-4bd4-bbd5-a6920e4c5653 + - 51300001-0023-4bd4-bbd5-a6920e4c5653 + - 45460001-0023-4bd4-bbd5-a6920e4c5653 + - 454c0001-0023-4bd4-bbd5-a6920e4c5653 + - 55300001-0023-4bd4-bbd5-a6920e4c5653 + - 53440001-0023-4bd4-bbd5-a6920e4c5653 + - 48300001-0023-4bd4-bbd5-a6920e4c5653 + - 46530001-0023-4bd4-bbd5-a6920e4c5653 + - 42410001-0023-4bd4-bbd5-a6920e4c5653 + - 43410001-0023-4bd4-bbd5-a6920e4c5653 + - 4f430001-0023-4bd4-bbd5-a6920e4c5653 + - 455a0001-0023-4bd4-bbd5-a6920e4c5653 services: 0000fff0-0000-1000-8000-00805f9b34fb: tx: 0000fff2-0000-1000-8000-00805f9b34fb From 6a62ddf11e51c19f9336269c94a5164d085c80d6 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Thu, 23 Jan 2025 16:02:55 +0000 Subject: [PATCH 15/22] feat: Adding support for Joyhub Viva --- .../build-config/buttplug-device-config-v3.json | 9 ++++++++- .../device-config-v3/buttplug-device-config-v3.yml | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 220e3161d..a5dee8d37 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -14800,6 +14800,12 @@ ], "name": "JoyHub Urica Guard 2" }, + { + "identifier": [ + "J-Viva" + ], + "name": "JoyHub Viva" + }, { "identifier": [ "J-Petalwish2" @@ -15164,7 +15170,8 @@ "J-DukeDazzle2", "J-Scarlett", "J-Tarik", - "J-UricaGuard2" + "J-UricaGuard2", + "J-Viva" ], "services": { "0000ffa0-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 86a9bf177..154280c5b 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -8470,6 +8470,9 @@ protocols: - identifier: - J-UricaGuard2 name: JoyHub Urica Guard 2 + - identifier: + - J-Viva + name: JoyHub Viva - identifier: - J-Petalwish2 name: JoyHub Petalwish 2 @@ -8693,6 +8696,7 @@ protocols: - J-Scarlett - J-Tarik - J-UricaGuard2 + - J-Viva services: 0000ffa0-0000-1000-8000-00805f9b34fb: tx: 0000ffa1-0000-1000-8000-00805f9b34fb From 25388939b765950d0a4d023e69362e99deb2c10f Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Mon, 27 Jan 2025 10:47:38 +0000 Subject: [PATCH 16/22] feat: Adding support for JoyHub Ryden --- .../build-config/buttplug-device-config-v3.json | 9 ++++++++- .../device-config-v3/buttplug-device-config-v3.yml | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index a5dee8d37..a265d7ac9 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -14806,6 +14806,12 @@ ], "name": "JoyHub Viva" }, + { + "identifier": [ + "J-Ryden" + ], + "name": "JoyHub Ryden" + }, { "identifier": [ "J-Petalwish2" @@ -15171,7 +15177,8 @@ "J-Scarlett", "J-Tarik", "J-UricaGuard2", - "J-Viva" + "J-Viva", + "J-Ryden" ], "services": { "0000ffa0-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 154280c5b..c168f6054 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -8473,6 +8473,9 @@ protocols: - identifier: - J-Viva name: JoyHub Viva + - identifier: + - J-Ryden + name: JoyHub Ryden - identifier: - J-Petalwish2 name: JoyHub Petalwish 2 @@ -8697,6 +8700,7 @@ protocols: - J-Tarik - J-UricaGuard2 - J-Viva + - J-Ryden services: 0000ffa0-0000-1000-8000-00805f9b34fb: tx: 0000ffa1-0000-1000-8000-00805f9b34fb From d13c19022a81225ac9a02e721bbdf867fd2e554b Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Mon, 27 Jan 2025 11:51:38 +0000 Subject: [PATCH 17/22] feat: Adding support for Svakom Coco Pro --- .../buttplug-device-config-v3.json | 42 +++++++++++++++++ .../buttplug-device-config-v3.yml | 23 +++++++++ buttplug/src/server/device/protocol/mod.rs | 5 ++ .../src/server/device/protocol/svakom_v6.rs | 47 +++++++++++++++++++ buttplug/tests/test_device_protocols.rs | 4 ++ .../device_test_case/test_svakom_cocopro.yaml | 42 +++++++++++++++++ 6 files changed, 163 insertions(+) create mode 100644 buttplug/src/server/device/protocol/svakom_v6.rs create mode 100644 buttplug/tests/util/device_test/device_test_case/test_svakom_cocopro.yaml diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index a265d7ac9..0134ff700 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -5837,6 +5837,48 @@ } ] }, + "svakom-v6": { + "defaults": { + "name": "Svakom Device v6", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 10 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + "configurations": [ + { + "identifier": [ + "CocoPro" + ], + "name": "Svakom Coco Pro" + } + ], + "communication": [ + { + "btle": { + "names": [ + "CocoPro" + ], + "services": { + "0000ffe0-0000-1000-8000-00805f9b34fb": { + "tx": "0000ffe1-0000-1000-8000-00805f9b34fb", + "rx": "0000ffe2-0000-1000-8000-00805f9b34fb" + } + } + } + } + ] + }, "svakom-sam": { "defaults": { "name": "Svakom Sam Neo", diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index c168f6054..93fcda352 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -3344,6 +3344,29 @@ protocols: 0000ffe0-0000-1000-8000-00805f9b34fb: tx: 0000ffe1-0000-1000-8000-00805f9b34fb rx: 0000ffe2-0000-1000-8000-00805f9b34fb + svakom-v6: + defaults: + name: Svakom Device v6 + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 10 + messages: + - ScalarCmd + configurations: + - identifier: + - CocoPro + name: Svakom Coco Pro + communication: + - btle: + names: + - CocoPro + services: + 0000ffe0-0000-1000-8000-00805f9b34fb: + tx: 0000ffe1-0000-1000-8000-00805f9b34fb + rx: 0000ffe2-0000-1000-8000-00805f9b34fb svakom-sam: defaults: name: Svakom Sam Neo diff --git a/buttplug/src/server/device/protocol/mod.rs b/buttplug/src/server/device/protocol/mod.rs index 22564d5ac..f53328ed6 100644 --- a/buttplug/src/server/device/protocol/mod.rs +++ b/buttplug/src/server/device/protocol/mod.rs @@ -120,6 +120,7 @@ pub mod svakom_v2; pub mod svakom_v3; pub mod svakom_v4; pub mod svakom_v5; +pub mod svakom_v6; pub mod synchro; pub mod tcode_v03; pub mod thehandy; @@ -587,6 +588,10 @@ pub fn get_default_protocol_map() -> HashMap super::ProtocolKeepaliveStrategy { + super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy + } + + fn handle_scalar_vibrate_cmd( + &self, + _index: u32, + scalar: u32, + ) -> Result, ButtplugDeviceError> { + Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + [ + 0x55, + 0x03, + 0x00, + 0x00, + if scalar == 0 { 0x00 } else { 0x01 }, + scalar as u8, + 0x00, + ] + .to_vec(), + false, + ) + .into()]) + } +} diff --git a/buttplug/tests/test_device_protocols.rs b/buttplug/tests/test_device_protocols.rs index ed65ab26d..14dd63942 100644 --- a/buttplug/tests/test_device_protocols.rs +++ b/buttplug/tests/test_device_protocols.rs @@ -92,6 +92,7 @@ async fn load_test_case(test_file: &str) -> DeviceTestCase { #[test_case("test_svakom_alex.yaml" ; "Svakom Alex Neo")] #[test_case("test_svakom_alex_v2.yaml" ; "Svakom Alex Neo 2")] #[test_case("test_svakom_iker.yaml" ; "Svakom Iker")] +#[test_case("test_svakom_cocopro.yaml" ; "Svakom Coco Pro")] #[test_case("test_svakom_barnard.yaml" ; "Svakom (Fantasy Cup) Barnard")] #[test_case("test_svakom_mora_neo.yaml" ; "Svakom Mora Neo")] #[test_case("test_fox_protocol.yaml" ; "Fox Protocol")] @@ -206,6 +207,7 @@ async fn test_device_protocols_embedded_v3(test_file: &str) { #[test_case("test_svakom_barnard.yaml" ; "Svakom (Fantasy Cup) Barnard")] #[test_case("test_svakom_mora_neo.yaml" ; "Svakom Mora Neo")] #[test_case("test_svakom_iker.yaml" ; "Svakom Iker")] +#[test_case("test_svakom_cocopro.yaml" ; "Svakom Coco Pro")] #[test_case("test_fox_protocol.yaml" ; "Fox Protocol")] #[test_case("test_sakuraneko_koikoi.yaml" ; "Sakuraneko Protocol - Koikoi")] #[test_case("test_xiuxiuda_protocol.yaml" ; "Xiuxiuda Protocol")] @@ -292,6 +294,7 @@ async fn test_device_protocols_json_v3(test_file: &str) { #[test_case("test_svakom_alex.yaml" ; "Svakom Alex Neo")] #[test_case("test_svakom_alex_v2.yaml" ; "Svakom Alex Neo 2")] #[test_case("test_svakom_iker.yaml" ; "Svakom Iker")] +#[test_case("test_svakom_cocopro.yaml" ; "Svakom Coco Pro")] #[test_case("test_fox_protocol.yaml" ; "Fox Protocol")] #[test_case("test_xiuxiuda_protocol.yaml" ; "Xiuxiuda Protocol")] #[test_case("test_adrienlastic_protocol.yaml" ; "Adrien Lastic Protocol")] @@ -371,6 +374,7 @@ async fn test_device_protocols_embedded_v2(test_file: &str) { #[test_case("test_svakom_alex.yaml" ; "Svakom Alex Neo")] #[test_case("test_svakom_alex_v2.yaml" ; "Svakom Alex Neo 2")] #[test_case("test_svakom_iker.yaml" ; "Svakom Iker")] +#[test_case("test_svakom_cocopro.yaml" ; "Svakom Coco Pro")] #[test_case("test_fox_protocol.yaml" ; "Fox Protocol")] #[test_case("test_xiuxiuda_protocol.yaml" ; "Xiuxiuda Protocol")] #[test_case("test_adrienlastic_protocol.yaml" ; "Adrien Lastic Protocol")] diff --git a/buttplug/tests/util/device_test/device_test_case/test_svakom_cocopro.yaml b/buttplug/tests/util/device_test/device_test_case/test_svakom_cocopro.yaml new file mode 100644 index 000000000..b39bfb74d --- /dev/null +++ b/buttplug/tests/util/device_test/device_test_case/test_svakom_cocopro.yaml @@ -0,0 +1,42 @@ +devices: + - identifier: + name: "CocoPro" + expected_name: "Svakom Coco Pro" +device_commands: + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 0.5 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x55, 0x03, 0x00, 0x00, 0x01, 0x05, 0x00] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 0.75 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x55, 0x03, 0x00, 0x00, 0x01, 0x08, 0x00] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Stop + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00] + write_with_response: false From 5b952547cdbce5b8a45229ee50593b24270ff384 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Thu, 3 Oct 2024 13:35:36 +0100 Subject: [PATCH 18/22] feat: Add support for the Joyroid Loob This change will required a fix in btleplug, as the LOOB has duplicate characteristic UUIDs and btleplug gave us the last one, not the first: see https://github.com/deviceplug/btleplug/commit/821623fcfd1fe8587d38cf40edec356c2a6b477a --- .../buttplug-device-config-v3.json | 35 +++++++++- .../buttplug-device-config-v3.yml | 20 +++++- buttplug/src/server/device/protocol/loob.rs | 66 +++++++++++++++++++ buttplug/src/server/device/protocol/mod.rs | 2 + buttplug/tests/test_device_protocols.rs | 4 ++ .../device_test_case/test_loob_protocol.yaml | 57 ++++++++++++++++ 6 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 buttplug/src/server/device/protocol/loob.rs create mode 100644 buttplug/tests/util/device_test/device_test_case/test_loob_protocol.yaml diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 0134ff700..76ec0cd8e 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -1,7 +1,7 @@ { "version": { "major": 3, - "minor": 11 + "minor": 12 }, "protocols": { "lovense": { @@ -18166,6 +18166,39 @@ } } ] + }, + "loob": { + "defaults": { + "name": "Joyroid Loob", + "features": [ + { + "feature-type": "Position", + "actuator": { + "step-range": [ + 0, + 1000 + ], + "messages": [ + "LinearCmd" + ] + } + } + ] + }, + "communication": [ + { + "btle": { + "names": [ + "LOOB" + ], + "services": { + "b75c49d2-04a3-4071-a0b5-35853eb08307": { + "tx": "ba5c49d2-04a3-4071-a0b5-35853eb08307" + } + } + } + } + ] } } } diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 93fcda352..13ac61451 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -1,6 +1,6 @@ version: major: 3 - minor: 11 + minor: 12 protocols: lovense: defaults: @@ -10418,3 +10418,21 @@ protocols: services: 0000ffa0-0000-1000-8000-00805f9b34fb: tx: 0000ffa1-0000-1000-8000-00805f9b34fb + loob: + defaults: + name: Joyroid Loob + features: + - feature-type: Position + actuator: + step-range: + - 0 + - 1000 + messages: + - LinearCmd + communication: + - btle: + names: + - LOOB + services: + b75c49d2-04a3-4071-a0b5-35853eb08307: + tx: ba5c49d2-04a3-4071-a0b5-35853eb08307 \ No newline at end of file diff --git a/buttplug/src/server/device/protocol/loob.rs b/buttplug/src/server/device/protocol/loob.rs new file mode 100644 index 000000000..8f598af6a --- /dev/null +++ b/buttplug/src/server/device/protocol/loob.rs @@ -0,0 +1,66 @@ +// Buttplug Rust Source Code File - See https://buttplug.io for more info. +// +// Copyright 2016-2025 Nonpolynomial Labs LLC. All rights reserved. +// +// Licensed under the BSD 3-Clause license. See LICENSE file in the project root +// for full license information. + +use crate::{ + core::{ + errors::ButtplugDeviceError, + message::{self, Endpoint}, + }, + server::device::{ + configuration::{ProtocolCommunicationSpecifier, UserDeviceDefinition, UserDeviceIdentifier}, + hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, + protocol::{ + generic_protocol_initializer_setup, + ProtocolHandler, + ProtocolIdentifier, + ProtocolInitializer, + }, + }, +}; +use async_trait::async_trait; +use std::cmp::{max, min}; +use std::sync::Arc; + +generic_protocol_initializer_setup!(Loob, "loob"); + +#[derive(Default)] +pub struct LoobInitializer {} + +#[async_trait] +impl ProtocolInitializer for LoobInitializer { + async fn initialize( + &mut self, + hardware: Arc, + _: &UserDeviceDefinition, + ) -> Result, ButtplugDeviceError> { + let msg = HardwareWriteCmd::new(Endpoint::Tx, vec![0x00, 0x01, 0x01, 0xf4], true); + hardware.write_value(&msg).await?; + Ok(Arc::new(Loob::default())) + } +} + +#[derive(Default)] +pub struct Loob {} + +impl ProtocolHandler for Loob { + fn handle_linear_cmd( + &self, + message: message::LinearCmdV4, + ) -> Result, ButtplugDeviceError> { + if let Some(vec) = message.vectors().get(0) { + let pos: u16 = max(min((vec.position() * 1000.0) as u16, 1000), 1); + let time: u16 = max(vec.duration() as u16, 1); + let mut data = pos.to_be_bytes().to_vec(); + for b in time.to_be_bytes() { + data.push(b); + } + Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, false).into()]) + } else { + Ok(vec![]) + } + } +} diff --git a/buttplug/src/server/device/protocol/mod.rs b/buttplug/src/server/device/protocol/mod.rs index f53328ed6..5c21633f6 100644 --- a/buttplug/src/server/device/protocol/mod.rs +++ b/buttplug/src/server/device/protocol/mod.rs @@ -60,6 +60,7 @@ pub mod libo_shark; pub mod libo_vibes; pub mod lioness; pub mod longlosttouch; +pub mod loob; pub mod lovedistance; pub mod lovehoney_desire; pub mod lovense; @@ -378,6 +379,7 @@ pub fn get_default_protocol_map() -> HashMap DeviceTestCase { #[test_case("test_longlosttouch_protocol.yaml" ; "LongLostTouch Protocol")] #[test_case("test_adrienlastic_protocol.yaml" ; "Adrien Lastic Protocol")] #[test_case("test_foreo_protocol.yaml" ; "Foreo Protocol")] +#[test_case("test_loob_protocol.yaml" ; "Joyroid Loob Protocol")] #[test_case("test_joyhub_petalwish.yaml" ; "JoyHub Protocol - Petalwish")] #[test_case("test_joyhub_petalwish_compat.yaml" ; "JoyHub Protocol - Petalwish Compat")] #[test_case("test_joyhub_roselin.yaml" ; "JoyHub Protocol - RoseLin")] @@ -213,6 +214,7 @@ async fn test_device_protocols_embedded_v3(test_file: &str) { #[test_case("test_xiuxiuda_protocol.yaml" ; "Xiuxiuda Protocol")] #[test_case("test_adrienlastic_protocol.yaml" ; "Adrien Lastic Protocol")] #[test_case("test_foreo_protocol.yaml" ; "Foreo Protocol")] +#[test_case("test_loob_protocol.yaml" ; "Joyroid Loob Protocol")] #[test_case("test_joyhub_petalwish.yaml" ; "JoyHub Protocol - Petalwish")] #[test_case("test_joyhub_petalwish_compat.yaml" ; "JoyHub Protocol - Petalwish Compat")] #[test_case("test_joyhub_moonhorn.yaml" ; "JoyHub Protocol - Moonhorn")] @@ -299,6 +301,7 @@ async fn test_device_protocols_json_v3(test_file: &str) { #[test_case("test_xiuxiuda_protocol.yaml" ; "Xiuxiuda Protocol")] #[test_case("test_adrienlastic_protocol.yaml" ; "Adrien Lastic Protocol")] #[test_case("test_foreo_protocol.yaml" ; "Foreo Protocol")] +#[test_case("test_loob_protocol.yaml" ; "Joyroid Loob Protocol")] #[test_case("test_joyhub_petalwish_compat.yaml" ; "JoyHub Protocol - Petalwish Compat")] #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] @@ -379,6 +382,7 @@ async fn test_device_protocols_embedded_v2(test_file: &str) { #[test_case("test_xiuxiuda_protocol.yaml" ; "Xiuxiuda Protocol")] #[test_case("test_adrienlastic_protocol.yaml" ; "Adrien Lastic Protocol")] #[test_case("test_foreo_protocol.yaml" ; "Foreo Protocol")] +#[test_case("test_loob_protocol.yaml" ; "Joyroid Loob Protocol")] #[test_case("test_joyhub_petalwish_compat.yaml" ; "JoyHub Protocol - Petalwish Compat")] #[test_case("test_itoys_protocol.yaml" ; "iToys Protocol")] #[test_case("test_leten_protocol.yaml" ; "Leten Protocol")] diff --git a/buttplug/tests/util/device_test/device_test_case/test_loob_protocol.yaml b/buttplug/tests/util/device_test/device_test_case/test_loob_protocol.yaml new file mode 100644 index 000000000..fa0ad2d2d --- /dev/null +++ b/buttplug/tests/util/device_test/device_test_case/test_loob_protocol.yaml @@ -0,0 +1,57 @@ +devices: + - identifier: + name: "LOOB" + expected_name: "Joyroid Loob" +device_init: + # Initialization + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x00, 0x01, 0x01, 0xf4] + write_with_response: true +device_commands: + # Commands + - !Messages + device_index: 0 + messages: + - !Linear + - Index: 0 + Position: 0.51 + Duration: 200 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x01, 0xfe, 0x00, 0xc8] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Linear + - Index: 0 + Position: 1.0 + Duration: 50 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x03, 0xe8, 0x00, 0x32] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Linear + - Index: 0 + Position: 0.0 + Duration: 500 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x00, 0x01, 0x01, 0xf4] + write_with_response: false From b25bec52b0f4a8833f517b85e2ede6d77c693c3d Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 28 Jan 2025 13:56:22 +0000 Subject: [PATCH 19/22] feat: Adding support for Bananasome Rocket X7 --- .../buttplug-device-config-v3.json | 57 +++++++++++++++++ .../buttplug-device-config-v3.yml | 34 +++++++++- .../src/server/device/protocol/bananasome.rs | 61 ++++++++++++++++++ buttplug/src/server/device/protocol/mod.rs | 5 ++ buttplug/tests/test_device_protocols.rs | 2 + .../test_bananasome_protocol.yaml | 62 +++++++++++++++++++ 6 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 buttplug/src/server/device/protocol/bananasome.rs create mode 100644 buttplug/tests/util/device_test/device_test_case/test_bananasome_protocol.yaml diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 76ec0cd8e..afcc42006 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -18199,6 +18199,63 @@ } } ] + }, + "bananasome": { + "defaults": { + "name": "Bananasome Rocket X7", + "features": [ + { + "feature-type": "Oscillate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 255 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + "communication": [ + { + "btle": { + "names": [ + "火箭X7" + ], + "services": { + "0000ae00-0000-1000-8000-00805f9b34fb": { + "tx": "0000ae01-0000-1000-8000-00805f9b34fb" + } + } + } + } + ] } } } diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 13ac61451..1141641be 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -10435,4 +10435,36 @@ protocols: - LOOB services: b75c49d2-04a3-4071-a0b5-35853eb08307: - tx: ba5c49d2-04a3-4071-a0b5-35853eb08307 \ No newline at end of file + tx: ba5c49d2-04a3-4071-a0b5-35853eb08307 + bananasome: + defaults: + name: Bananasome Rocket X7 + features: + - feature-type: Oscillate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 255 + messages: + - ScalarCmd + communication: + - btle: + names: + - 火箭X7 + services: + 0000ae00-0000-1000-8000-00805f9b34fb: + tx: 0000ae01-0000-1000-8000-00805f9b34fb \ No newline at end of file diff --git a/buttplug/src/server/device/protocol/bananasome.rs b/buttplug/src/server/device/protocol/bananasome.rs new file mode 100644 index 000000000..3b58cbc3a --- /dev/null +++ b/buttplug/src/server/device/protocol/bananasome.rs @@ -0,0 +1,61 @@ +// Buttplug Rust Source Code File - See https://buttplug.io for more info. +// +// Copyright 2016-2025 Nonpolynomial Labs LLC. All rights reserved. +// +// Licensed under the BSD 3-Clause license. See LICENSE file in the project root +// for full license information. + +use crate::{ + core::{ + errors::ButtplugDeviceError, + message::{ + ActuatorType, + ActuatorType::{Oscillate, Vibrate}, + Endpoint, + }, + }, + server::device::{ + hardware::{HardwareCommand, HardwareWriteCmd}, + protocol::{generic_protocol_setup, ProtocolHandler}, + }, +}; + +generic_protocol_setup!(Bananasome, "bananasome"); + +#[derive(Default)] +pub struct Bananasome {} + +impl ProtocolHandler for Bananasome { + fn keepalive_strategy(&self) -> super::ProtocolKeepaliveStrategy { + super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy + } + + fn needs_full_command_set(&self) -> bool { + true + } + fn handle_scalar_cmd( + &self, + commands: &[Option<(ActuatorType, u32)>], + ) -> Result, ButtplugDeviceError> { + Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![ + 0xa0, + 0x03, + commands[0].unwrap_or((Oscillate, 0)).1 as u8, + if commands.len() > 1 { + commands[1].unwrap_or((Vibrate, 0)).1 + } else { + 0 + } as u8, + if commands.len() > 2 { + commands[2].unwrap_or((Vibrate, 0)).1 + } else { + 0 + } as u8, + ], + false, + ) + .into()]) + } +} diff --git a/buttplug/src/server/device/protocol/mod.rs b/buttplug/src/server/device/protocol/mod.rs index 5c21633f6..2a54a1ff5 100644 --- a/buttplug/src/server/device/protocol/mod.rs +++ b/buttplug/src/server/device/protocol/mod.rs @@ -18,6 +18,7 @@ pub mod adrienlastic; pub mod amorelie_joy; pub mod aneros; pub mod ankni; +pub mod bananasome; pub mod buttplug_passthru; pub mod cachito; pub mod cowgirl; @@ -234,6 +235,10 @@ pub fn get_default_protocol_map() -> HashMap DeviceTestCase { #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[test_case("test_luvmazer_protocol.yaml" ; "Luvmazer Protocol")] +#[test_case("test_bananasome_protocol.yaml" ; "Bananasome Protocol")] #[tokio::test] async fn test_device_protocols_embedded_v3(test_file: &str) { //tracing_subscriber::fmt::init(); @@ -236,6 +237,7 @@ async fn test_device_protocols_embedded_v3(test_file: &str) { #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[test_case("test_luvmazer_protocol.yaml" ; "Luvmazer Protocol")] +#[test_case("test_bananasome_protocol.yaml" ; "Bananasome Protocol")] #[tokio::test] async fn test_device_protocols_json_v3(test_file: &str) { //tracing_subscriber::fmt::init(); diff --git a/buttplug/tests/util/device_test/device_test_case/test_bananasome_protocol.yaml b/buttplug/tests/util/device_test/device_test_case/test_bananasome_protocol.yaml new file mode 100644 index 000000000..328809bc7 --- /dev/null +++ b/buttplug/tests/util/device_test/device_test_case/test_bananasome_protocol.yaml @@ -0,0 +1,62 @@ +devices: + - identifier: + name: "火箭X7" + expected_name: "Bananasome Rocket X7" +device_commands: + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 0.5 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa0, 0x03, 0x00, 0x80, 0x00] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 1 + Speed: 0.5 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa0, 0x03, 0x00, 0x80, 0x80] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Scalar + - Index: 0 + Scalar: 0.75 + ActuatorType: Oscillate + - Index: 1 + Scalar: 0.75 + ActuatorType: Vibrate + - Index: 2 + Scalar: 0.25 + ActuatorType: Vibrate + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa0, 0x03, 0xc0, 0xc0, 0x40] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Stop + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa0, 0x03, 0x00, 0x00, 0x00] + write_with_response: false From e9d8cf49ec0966be7a445efbccc73de8076e8102 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Mon, 3 Feb 2025 09:44:13 +0000 Subject: [PATCH 20/22] feat: Adding support for the Omobo ViVegg Vibrator (S6) and Kisstoy Lost (3 versions) --- .../buttplug-device-config-v3.json | 183 ++++++++++++++++++ .../buttplug-device-config-v3.yml | 107 +++++++++- buttplug/src/server/device/protocol/mod.rs | 2 + buttplug/src/server/device/protocol/omobo.rs | 38 ++++ buttplug/tests/test_device_protocols.rs | 4 + .../device_test_case/test_omobo_protocol.yaml | 43 ++++ 6 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 buttplug/src/server/device/protocol/omobo.rs create mode 100644 buttplug/tests/util/device_test/device_test_case/test_omobo_protocol.yaml diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index afcc42006..57673f521 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -13289,6 +13289,153 @@ } ] }, + { + "identifier": [ + "QCVW" + ], + "name": "Kisstoy Lost (Vibrating)", + "features": [ + { + "feature-type": "Vibrate", + "description": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "description": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Battery", + "description": "Battery Level", + "sensor": { + "value-range": [ + [ + 0, + 100 + ] + ], + "messages": [ + "SensorReadCmd" + ] + } + } + ] + }, + { + "identifier": [ + "QCSW" + ], + "name": "Kisstoy Lost (Sucking)", + "features": [ + { + "feature-type": "Vibrate", + "description": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "description": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Battery", + "description": "Battery Level", + "sensor": { + "value-range": [ + [ + 0, + 100 + ] + ], + "messages": [ + "SensorReadCmd" + ] + } + } + ] + }, + { + "identifier": [ + "QCPW" + ], + "name": "Kisstoy Lost (Insertable)", + "features": [ + { + "feature-type": "Vibrate", + "description": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Vibrate", + "description": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Battery", + "description": "Battery Level", + "sensor": { + "value-range": [ + [ + 0, + 100 + ] + ], + "messages": [ + "SensorReadCmd" + ] + } + } + ] + }, { "identifier": [ "TFG1" @@ -13610,6 +13757,9 @@ "G403", "G43A", "K12B", + "QCVW", + "QCSW", + "QCPW", "TFG1", "GK27", "GK25", @@ -18256,6 +18406,39 @@ } } ] + }, + "omobo": { + "defaults": { + "name": "Omobo ViVegg Vibrator", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, + "communication": [ + { + "btle": { + "names": [ + "S6" + ], + "services": { + "0000ffb0-0000-1000-8000-00805f9b34fb": { + "tx": "0000ffb2-0000-1000-8000-00805f9b34fb" + } + } + } + } + ] } } } diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 1141641be..f1e7fbfe1 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -7558,6 +7558,90 @@ protocols: - 100 messages: - SensorReadCmd + - identifier: + - QCVW + name: Kisstoy Lost (Vibrating) + features: + - feature-type: Vibrate + description: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Vibrate + description: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Battery + description: Battery Level + sensor: + value-range: + - - 0 + - 100 + messages: + - SensorReadCmd + - identifier: + - QCSW + name: Kisstoy Lost (Sucking) + features: + - feature-type: Vibrate + description: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Vibrate + description: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Battery + description: Battery Level + sensor: + value-range: + - - 0 + - 100 + messages: + - SensorReadCmd + - identifier: + - QCPW + name: Kisstoy Lost (Insertable) + features: + - feature-type: Vibrate + description: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Vibrate + description: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Battery + description: Battery Level + sensor: + value-range: + - - 0 + - 100 + messages: + - SensorReadCmd # Type 2 - identifier: - TFG1 @@ -7780,6 +7864,9 @@ protocols: - G403 - G43A - K12B + - QCVW + - QCSW + - QCPW # Type 2 - TFG1 - GK27 @@ -10467,4 +10554,22 @@ protocols: - 火箭X7 services: 0000ae00-0000-1000-8000-00805f9b34fb: - tx: 0000ae01-0000-1000-8000-00805f9b34fb \ No newline at end of file + tx: 0000ae01-0000-1000-8000-00805f9b34fb + omobo: + defaults: + name: Omobo ViVegg Vibrator + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + communication: + - btle: + names: + - S6 + services: + 0000ffb0-0000-1000-8000-00805f9b34fb: + tx: 0000ffb2-0000-1000-8000-00805f9b34fb \ No newline at end of file diff --git a/buttplug/src/server/device/protocol/mod.rs b/buttplug/src/server/device/protocol/mod.rs index 2a54a1ff5..b55bddb57 100644 --- a/buttplug/src/server/device/protocol/mod.rs +++ b/buttplug/src/server/device/protocol/mod.rs @@ -91,6 +91,7 @@ pub mod nextlevelracing; pub mod nexus_revo; pub mod nintendo_joycon; pub mod nobra; +pub mod omobo; pub mod patoo; pub mod picobong; pub mod pink_punch; @@ -486,6 +487,7 @@ pub fn get_default_protocol_map() -> HashMap super::ProtocolKeepaliveStrategy { + super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy + } + + fn handle_scalar_vibrate_cmd( + &self, + _index: u32, + scalar: u32, + ) -> Result, ButtplugDeviceError> { + Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0xa1, 0x04, 0x04, 0x01, scalar as u8, 0xff, 0x55], + true, + ) + .into()]) + } +} diff --git a/buttplug/tests/test_device_protocols.rs b/buttplug/tests/test_device_protocols.rs index f6e212bf1..b2f263a44 100644 --- a/buttplug/tests/test_device_protocols.rs +++ b/buttplug/tests/test_device_protocols.rs @@ -124,6 +124,7 @@ async fn load_test_case(test_file: &str) -> DeviceTestCase { #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[test_case("test_luvmazer_protocol.yaml" ; "Luvmazer Protocol")] #[test_case("test_bananasome_protocol.yaml" ; "Bananasome Protocol")] +#[test_case("test_omobo_protocol.yaml" ; "Omobo Protocol")] #[tokio::test] async fn test_device_protocols_embedded_v3(test_file: &str) { //tracing_subscriber::fmt::init(); @@ -238,6 +239,7 @@ async fn test_device_protocols_embedded_v3(test_file: &str) { #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[test_case("test_luvmazer_protocol.yaml" ; "Luvmazer Protocol")] #[test_case("test_bananasome_protocol.yaml" ; "Bananasome Protocol")] +#[test_case("test_omobo_protocol.yaml" ; "Omobo Protocol")] #[tokio::test] async fn test_device_protocols_json_v3(test_file: &str) { //tracing_subscriber::fmt::init(); @@ -320,6 +322,7 @@ async fn test_device_protocols_json_v3(test_file: &str) { #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] +#[test_case("test_omobo_protocol.yaml" ; "Omobo Protocol")] #[tokio::test] async fn test_device_protocols_embedded_v2(test_file: &str) { util::device_test::client::client_v2::run_embedded_test_case(&load_test_case(test_file).await) @@ -401,6 +404,7 @@ async fn test_device_protocols_embedded_v2(test_file: &str) { #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] +#[test_case("test_omobo_protocol.yaml" ; "Omobo Protocol")] #[tokio::test] async fn test_device_protocols_json_v2(test_file: &str) { util::device_test::client::client_v2::run_json_test_case(&load_test_case(test_file).await).await; diff --git a/buttplug/tests/util/device_test/device_test_case/test_omobo_protocol.yaml b/buttplug/tests/util/device_test/device_test_case/test_omobo_protocol.yaml new file mode 100644 index 000000000..d8ab38dc5 --- /dev/null +++ b/buttplug/tests/util/device_test/device_test_case/test_omobo_protocol.yaml @@ -0,0 +1,43 @@ +devices: + - identifier: + name: "S6" + expected_name: "Omobo ViVegg Vibrator" +device_commands: + # Commands + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 0.5 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa1, 0x04, 0x04, 0x01, 0x32, 0xff, 0x55] + write_with_response: true + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 1.0 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa1, 0x04, 0x04, 0x01, 0x64, 0xff, 0x55] + write_with_response: true + - !Messages + device_index: 0 + messages: + - !Stop + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0xa1, 0x04, 0x04, 0x01, 0x00, 0xff, 0x55] + write_with_response: true From 0f69993f9b659acd3b759edd21d1d9b7f26b3db8 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 4 Feb 2025 10:14:32 +0000 Subject: [PATCH 21/22] feat: Adding support for Kiiroo Spot and WeVibe Wand 2 --- .../buttplug-device-config-v3.json | 72 +++++++++++++++++++ .../buttplug-device-config-v3.yml | 40 +++++++++++ .../src/server/device/protocol/kiiroo_spot.rs | 64 +++++++++++++++++ buttplug/src/server/device/protocol/mod.rs | 5 ++ buttplug/tests/test_device_protocols.rs | 4 ++ .../device_test_case/test_kiiroo_spot.yaml | 43 +++++++++++ 6 files changed, 228 insertions(+) create mode 100644 buttplug/src/server/device/protocol/kiiroo_spot.rs create mode 100644 buttplug/tests/util/device_test/device_test_case/test_kiiroo_spot.yaml diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index 57673f521..ba2a53b73 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -3773,6 +3773,26 @@ } ] }, + { + "identifier": [ + "Wand 2" + ], + "name": "WeVibe Wand 2", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 22 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, { "identifier": [ "Bond", @@ -3843,6 +3863,7 @@ "Moxie", "Vector", "Wand", + "Wand 2", "Bond", "Nelson", "Nova2", @@ -4929,6 +4950,57 @@ } ] }, + "kiiroo-spot": { + "defaults": { + "name": "Kiiroo Spot", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Battery", + "description": "Battery Level", + "sensor": { + "value-range": [ + [ + 0, + 100 + ] + ], + "messages": [ + "SensorReadCmd" + ] + } + } + ] + }, + "communication": [ + { + "btle": { + "names": [ + "SPOT W1" + ], + "services": { + "00001400-0000-1000-8000-00805f9b34fb": { + "tx": "00001401-0000-1000-8000-00805f9b34fb" + }, + "0000180f-0000-1000-8000-00805f9b34fb": { + "rxblebattery": "00002a19-0000-1000-8000-00805f9b34fb" + } + } + } + } + ] + }, "vorze-cyclone-x": { "defaults": { "name": "Vorze Cyclone X10 Device", diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index f1e7fbfe1..426f6bbaa 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -2166,6 +2166,17 @@ protocols: - 22 messages: - ScalarCmd + - identifier: + - Wand 2 + name: WeVibe Wand 2 + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 22 + messages: + - ScalarCmd - identifier: - Bond - Nelson @@ -2208,6 +2219,7 @@ protocols: - Moxie - Vector - Wand + - Wand 2 - Bond - Nelson - Nova2 @@ -2833,6 +2845,34 @@ protocols: tx: 00001401-0000-1000-8000-00805f9b34fb 0000180f-0000-1000-8000-00805f9b34fb: rxblebattery: 00002a19-0000-1000-8000-00805f9b34fb + kiiroo-spot: + defaults: + name: Kiiroo Spot + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Battery + description: Battery Level + sensor: + value-range: + - - 0 + - 100 + messages: + - SensorReadCmd + communication: + - btle: + names: + - SPOT W1 + services: + 00001400-0000-1000-8000-00805f9b34fb: + tx: 00001401-0000-1000-8000-00805f9b34fb + 0000180f-0000-1000-8000-00805f9b34fb: + rxblebattery: 00002a19-0000-1000-8000-00805f9b34fb vorze-cyclone-x: defaults: name: Vorze Cyclone X10 Device diff --git a/buttplug/src/server/device/protocol/kiiroo_spot.rs b/buttplug/src/server/device/protocol/kiiroo_spot.rs new file mode 100644 index 000000000..b65a5e44b --- /dev/null +++ b/buttplug/src/server/device/protocol/kiiroo_spot.rs @@ -0,0 +1,64 @@ +// Buttplug Rust Source Code File - See https://buttplug.io for more info. +// +// Copyright 2016-2025 Nonpolynomial Labs LLC. All rights reserved. +// +// Licensed under the BSD 3-Clause license. See LICENSE file in the project root +// for full license information. + +use crate::{ + core::{ + errors::ButtplugDeviceError, + message::{self, ButtplugDeviceMessage, Endpoint, SensorReadingV4}, + }, + server::device::{ + hardware::{Hardware, HardwareCommand, HardwareReadCmd, HardwareWriteCmd}, + protocol::{generic_protocol_setup, ProtocolHandler}, + }, +}; +use futures::{future::BoxFuture, FutureExt}; +use std::{default::Default, sync::Arc}; + +generic_protocol_setup!(KiirooSpot, "kiiroo-spot"); + +#[derive(Default)] +pub struct KiirooSpot {} + +impl ProtocolHandler for KiirooSpot { + fn handle_scalar_vibrate_cmd( + &self, + _: u32, + scalar: u32, + ) -> Result, ButtplugDeviceError> { + Ok(vec![HardwareWriteCmd::new( + Endpoint::Tx, + vec![0x00, 0xff, 0x00, 0x00, 0x00, scalar as u8], + false, + ) + .into()]) + } + + fn handle_battery_level_cmd( + &self, + device: Arc, + message: message::SensorReadCmdV4, + ) -> BoxFuture> { + debug!("Trying to get battery reading."); + let message = message.clone(); + let msg = HardwareReadCmd::new(Endpoint::RxBLEBattery, 20, 0); + let fut = device.read_value(&msg); + async move { + let hw_msg = fut.await?; + let data = hw_msg.data(); + let battery_level = data[0] as i32; + let battery_reading = message::SensorReadingV4::new( + message.device_index(), + *message.feature_index(), + *message.sensor_type(), + vec![battery_level], + ); + debug!("Got battery reading: {}", battery_level); + Ok(battery_reading) + } + .boxed() + } +} diff --git a/buttplug/src/server/device/protocol/mod.rs b/buttplug/src/server/device/protocol/mod.rs index b55bddb57..0d5af1507 100644 --- a/buttplug/src/server/device/protocol/mod.rs +++ b/buttplug/src/server/device/protocol/mod.rs @@ -47,6 +47,7 @@ pub mod joyhub_v5; pub mod joyhub_v6; pub mod kgoal_boost; pub mod kiiroo_prowand; +pub mod kiiroo_spot; pub mod kiiroo_v2; pub mod kiiroo_v21; pub mod kiiroo_v21_initialized; @@ -335,6 +336,10 @@ pub fn get_default_protocol_map() -> HashMap DeviceTestCase { #[test_case("test_tcode_linear_and_vibrate.yaml" ; "TCode (Linear + Vibrate)")] #[test_case("test_serveu_protocol.yaml" ; "ServeU")] #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] +#[test_case("test_kiiroo_spot.yaml" ; "Kiiroo Spot Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[test_case("test_luvmazer_protocol.yaml" ; "Luvmazer Protocol")] @@ -235,6 +236,7 @@ async fn test_device_protocols_embedded_v3(test_file: &str) { #[test_case("test_tcode_linear_and_vibrate.yaml" ; "TCode (Linear + Vibrate)")] #[test_case("test_serveu_protocol.yaml" ; "ServeU")] #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] +#[test_case("test_kiiroo_spot.yaml" ; "Kiiroo Spot Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[test_case("test_luvmazer_protocol.yaml" ; "Luvmazer Protocol")] @@ -320,6 +322,7 @@ async fn test_device_protocols_json_v3(test_file: &str) { #[test_case("test_tcode_linear_and_vibrate.yaml" ; "TCode (Linear + Vibrate)")] #[test_case("test_serveu_protocol.yaml" ; "ServeU")] #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] +#[test_case("test_kiiroo_spot.yaml" ; "Kiiroo Spot Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[test_case("test_omobo_protocol.yaml" ; "Omobo Protocol")] @@ -402,6 +405,7 @@ async fn test_device_protocols_embedded_v2(test_file: &str) { #[test_case("test_tcode_linear_and_vibrate.yaml" ; "TCode (Linear + Vibrate)")] #[test_case("test_serveu_protocol.yaml" ; "ServeU")] #[test_case("test_kiiroo_prowand.yaml" ; "Kiiroo ProWand Protocol")] +#[test_case("test_kiiroo_spot.yaml" ; "Kiiroo Spot Protocol")] #[test_case("test_fleshy_thrust_protocol.yaml" ; "Fleshy Thrust Sync Protocol")] #[test_case("test_nexus_revo.yaml" ; "Nexus Revo Protocol")] #[test_case("test_omobo_protocol.yaml" ; "Omobo Protocol")] diff --git a/buttplug/tests/util/device_test/device_test_case/test_kiiroo_spot.yaml b/buttplug/tests/util/device_test/device_test_case/test_kiiroo_spot.yaml new file mode 100644 index 000000000..8c95c82e8 --- /dev/null +++ b/buttplug/tests/util/device_test/device_test_case/test_kiiroo_spot.yaml @@ -0,0 +1,43 @@ +devices: + - identifier: + name: "SPOT W1" + expected_name: "Kiiroo Spot" +device_commands: + # Commands + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 0.5 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x00, 0xff, 0x00, 0x00, 0x00, 0x32] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Vibrate + - Index: 0 + Speed: 1.0 + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x00, 0xff, 0x00, 0x00, 0x00, 0x64] + write_with_response: false + - !Messages + device_index: 0 + messages: + - !Stop + - !Commands + device_index: 0 + commands: + - !Write + endpoint: tx + data: [0x00, 0xff, 0x00, 0x00, 0x00, 0x00] + write_with_response: false From 1086b9cac65a04e3cada2495b5f6421922191eb8 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Thu, 6 Feb 2025 08:44:59 +0000 Subject: [PATCH 22/22] feat: Adding support for 2 Sensee devices: Easylive Vader and Little Seahorse --- .../buttplug-device-config-v3.json | 68 ++++++++++++++++++- .../buttplug-device-config-v3.yml | 38 +++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json index ba2a53b73..e6eb3a007 100644 --- a/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json +++ b/buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json @@ -13990,6 +13990,38 @@ } ] }, + { + "identifier": [ + "CCP322S5" + ], + "name": "Easylive Vader", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Oscillate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, { "identifier": [ "CTY508S5" @@ -14054,6 +14086,38 @@ } ] }, + { + "identifier": [ + "CTY823S5" + ], + "name": "Sensee Little Seahorse", + "features": [ + { + "feature-type": "Vibrate", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + }, + { + "feature-type": "Constrict", + "actuator": { + "step-range": [ + 0, + 100 + ], + "messages": [ + "ScalarCmd" + ] + } + } + ] + }, { "identifier": [ "CTY916S4" @@ -14096,7 +14160,9 @@ "Easylive NO8 Cup", "CTY508S5", "CTY916S4", - "PTYB22S2" + "PTYB22S2", + "CCP322S5", + "CTY823S5" ], "services": { "0000fff0-0000-1000-8000-00805f9b34fb": { diff --git a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml index 426f6bbaa..8d8834eba 100644 --- a/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml +++ b/buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml @@ -7997,6 +7997,24 @@ protocols: - 100 messages: - ScalarCmd + - identifier: + - CCP322S5 + name: Easylive Vader + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Oscillate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd - identifier: - CTY508S5 name: Sensee Voice-Interactive Female Vibrator @@ -8033,6 +8051,24 @@ protocols: - 100 messages: - ScalarCmd + - identifier: + - CTY823S5 + name: Sensee Little Seahorse + features: + - feature-type: Vibrate + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd + - feature-type: Constrict + actuator: + step-range: + - 0 + - 100 + messages: + - ScalarCmd - identifier: - CTY916S4 name: Sensee Dream Stick @@ -8060,6 +8096,8 @@ protocols: - CTY508S5 - CTY916S4 - PTYB22S2 + - CCP322S5 + - CTY823S5 services: 0000fff0-0000-1000-8000-00805f9b34fb: tx: 0000fff5-0000-1000-8000-00805f9b34fb