Skip to content

Commit 91c93f0

Browse files
blackspherefollowerqdot
authored andcommitted
feat: Adding support for TryFun Meta 2 and Black Hole Plus
1 parent 34cbc9c commit 91c93f0

File tree

8 files changed

+507
-0
lines changed

8 files changed

+507
-0
lines changed

buttplug/buttplug-device-config/build-config/buttplug-device-config-v3.json

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10941,6 +10941,108 @@
1094110941
}
1094210942
]
1094310943
},
10944+
"tryfun-meta2": {
10945+
"defaults": {
10946+
"name": "TryFun Meta 2",
10947+
"features": [
10948+
{
10949+
"feature-type": "Oscillate",
10950+
"actuator": {
10951+
"step-range": [
10952+
0,
10953+
100
10954+
],
10955+
"messages": [
10956+
"ScalarCmd"
10957+
]
10958+
}
10959+
},
10960+
{
10961+
"feature-type": "Rotate",
10962+
"actuator": {
10963+
"step-range": [
10964+
0,
10965+
100
10966+
],
10967+
"messages": [
10968+
"RotateCmd"
10969+
]
10970+
}
10971+
},
10972+
{
10973+
"feature-type": "Vibrate",
10974+
"actuator": {
10975+
"step-range": [
10976+
0,
10977+
100
10978+
],
10979+
"messages": [
10980+
"ScalarCmd"
10981+
]
10982+
}
10983+
}
10984+
]
10985+
},
10986+
"communication": [
10987+
{
10988+
"btle": {
10989+
"names": [
10990+
"TF-META2"
10991+
],
10992+
"services": {
10993+
"0000ffac-0000-1000-8000-00805f9b34fb": {
10994+
"tx": "0000ffb7-0000-1000-8000-00805f9b34fb"
10995+
}
10996+
}
10997+
}
10998+
}
10999+
]
11000+
},
11001+
"tryfun-blackhole": {
11002+
"defaults": {
11003+
"name": "TryFun Black Hole Plus",
11004+
"features": [
11005+
{
11006+
"feature-type": "Oscillate",
11007+
"actuator": {
11008+
"step-range": [
11009+
0,
11010+
100
11011+
],
11012+
"messages": [
11013+
"ScalarCmd"
11014+
]
11015+
}
11016+
},
11017+
{
11018+
"feature-type": "Vibrate",
11019+
"actuator": {
11020+
"step-range": [
11021+
0,
11022+
100
11023+
],
11024+
"messages": [
11025+
"ScalarCmd"
11026+
]
11027+
}
11028+
}
11029+
]
11030+
},
11031+
"communication": [
11032+
{
11033+
"btle": {
11034+
"names": [
11035+
"TF-BHPLUS"
11036+
],
11037+
"services": {
11038+
"0000ffac-0000-1000-8000-00805f9b34fb": {
11039+
"tx": "0000ffb7-0000-1000-8000-00805f9b34fb"
11040+
}
11041+
}
11042+
}
11043+
}
11044+
]
11045+
},
1094411046
"metaxsire": {
1094511047
"defaults": {
1094611048
"name": "metaXsire Device",

buttplug/buttplug-device-config/device-config-v3/buttplug-device-config-v3.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6244,6 +6244,63 @@ protocols:
62446244
tx: 0000fff1-0000-1000-8000-00805f9b34fb
62456245
0000ffac-0000-1000-8000-00805f9b34fb:
62466246
tx: 0000ffb5-0000-1000-8000-00805f9b34fb
6247+
tryfun-meta2:
6248+
defaults:
6249+
name: TryFun Meta 2
6250+
features:
6251+
- feature-type: Oscillate
6252+
actuator:
6253+
step-range:
6254+
- 0
6255+
- 100
6256+
messages:
6257+
- ScalarCmd
6258+
- feature-type: Vibrate
6259+
actuator:
6260+
step-range:
6261+
- 0
6262+
- 100
6263+
messages:
6264+
- ScalarCmd
6265+
- feature-type: Rotate
6266+
actuator:
6267+
step-range:
6268+
- 0
6269+
- 100
6270+
messages:
6271+
- RotateCmd
6272+
communication:
6273+
- btle:
6274+
names:
6275+
- TF-META2
6276+
services:
6277+
0000ffac-0000-1000-8000-00805f9b34fb:
6278+
tx: 0000ffb7-0000-1000-8000-00805f9b34fb
6279+
tryfun-blackhole:
6280+
defaults:
6281+
name: TryFun Black Hole Plus
6282+
features:
6283+
- feature-type: Oscillate
6284+
actuator:
6285+
step-range:
6286+
- 0
6287+
- 100
6288+
messages:
6289+
- ScalarCmd
6290+
- feature-type: Vibrate
6291+
actuator:
6292+
step-range:
6293+
- 0
6294+
- 100
6295+
messages:
6296+
- ScalarCmd
6297+
communication:
6298+
- btle:
6299+
names:
6300+
- TF-BHPLUS
6301+
services:
6302+
0000ffac-0000-1000-8000-00805f9b34fb:
6303+
tx: 0000ffb7-0000-1000-8000-00805f9b34fb
62476304
metaxsire:
62486305
defaults:
62496306
name: metaXsire Device

buttplug/src/server/device/protocol/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ pub mod synchro;
129129
pub mod tcode_v03;
130130
pub mod thehandy;
131131
pub mod tryfun;
132+
pub mod tryfun_blackhole;
133+
pub mod tryfun_meta2;
132134
pub mod vibcrafter;
133135
pub mod vibratissimo;
134136
pub mod vorze_sa;
@@ -611,6 +613,8 @@ pub fn get_default_protocol_map() -> HashMap<String, Arc<dyn ProtocolIdentifierF
611613
synchro::setup::SynchroIdentifierFactory::default(),
612614
);
613615
add_to_protocol_map(&mut map, tryfun::setup::TryFunIdentifierFactory::default());
616+
add_to_protocol_map(&mut map, tryfun_blackhole::setup::TryFunBlackHoleIdentifierFactory::default());
617+
add_to_protocol_map(&mut map, tryfun_meta2::setup::TryFunMeta2IdentifierFactory::default());
614618
add_to_protocol_map(
615619
&mut map,
616620
tcode_v03::setup::TCodeV03IdentifierFactory::default(),
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2+
//
3+
// Copyright 2016-2025 Nonpolynomial Labs LLC. All rights reserved.
4+
//
5+
// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6+
// for full license information.
7+
8+
use std::sync::atomic::{AtomicU8, Ordering};
9+
use crate::{
10+
core::{errors::ButtplugDeviceError, message::Endpoint},
11+
generic_protocol_setup,
12+
server::device::{
13+
hardware::{HardwareCommand, HardwareWriteCmd},
14+
protocol::ProtocolHandler,
15+
},
16+
};
17+
18+
generic_protocol_setup!(TryFunBlackHole, "tryfun-blackhole");
19+
20+
#[derive(Default)]
21+
pub struct TryFunBlackHole {
22+
packet_id: AtomicU8,
23+
}
24+
25+
impl ProtocolHandler for TryFunBlackHole {
26+
fn keepalive_strategy(&self) -> super::ProtocolKeepaliveStrategy {
27+
super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy
28+
}
29+
30+
fn handle_scalar_oscillate_cmd(
31+
&self,
32+
_index: u32,
33+
scalar: u32,
34+
) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
35+
let mut sum: u8 = 0xff;
36+
let mut data = vec![self.packet_id.fetch_add(1, Ordering::Relaxed), 0x02, 0x00, 0x03, 0x0c, scalar as u8];
37+
let mut count = 1;
38+
for item in data.iter().skip(1) {
39+
sum -= item;
40+
count += 1;
41+
}
42+
sum += count;
43+
data.push(sum);
44+
45+
Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, false).into()])
46+
}
47+
48+
fn handle_scalar_vibrate_cmd(
49+
&self,
50+
_index: u32,
51+
scalar: u32,
52+
) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
53+
let mut sum: u8 = 0xff;
54+
let mut data = vec![self.packet_id.fetch_add(1, Ordering::Relaxed), 0x02, 0x00, 0x03, 0x09, scalar as u8];
55+
let mut count = 1;
56+
for item in data.iter().skip(1) {
57+
sum -= item;
58+
count += 1;
59+
}
60+
sum += count;
61+
data.push(sum);
62+
63+
Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, false).into()])
64+
}
65+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2+
//
3+
// Copyright 2016-2025 Nonpolynomial Labs LLC. All rights reserved.
4+
//
5+
// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6+
// for full license information.
7+
8+
use std::sync::atomic::{AtomicU8, Ordering};
9+
use crate::{
10+
core::{errors::ButtplugDeviceError, message::Endpoint},
11+
generic_protocol_setup,
12+
server::device::{
13+
hardware::{HardwareCommand, HardwareWriteCmd},
14+
protocol::ProtocolHandler,
15+
},
16+
};
17+
18+
generic_protocol_setup!(TryFunMeta2, "tryfun-meta2");
19+
20+
#[derive(Default)]
21+
pub struct TryFunMeta2 {
22+
packet_id: AtomicU8,
23+
}
24+
25+
impl ProtocolHandler for TryFunMeta2 {
26+
fn keepalive_strategy(&self) -> super::ProtocolKeepaliveStrategy {
27+
super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy
28+
}
29+
30+
fn handle_scalar_oscillate_cmd(
31+
&self,
32+
_index: u32,
33+
scalar: u32,
34+
) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
35+
let mut sum: u8 = 0xff;
36+
let mut data = vec![self.packet_id.fetch_add(1, Ordering::Relaxed), 0x02, 0x00, 0x05, 0x21, 0x05, 0x0b, scalar as u8];
37+
let mut count = 1;
38+
for item in data.iter().skip(1) {
39+
sum -= item;
40+
count += 1;
41+
}
42+
sum += count;
43+
data.push(sum);
44+
45+
Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, false).into()])
46+
}
47+
48+
fn handle_rotate_cmd(&self, commands: &[Option<(u32, bool)>]) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
49+
if commands.len() >= 1 {
50+
if let Some(cmd) = commands[0] {
51+
let mut speed = cmd.0 as i8;
52+
if cmd.1 {
53+
speed += 1;
54+
speed *= -1;
55+
}
56+
let mut sum: u8 = 0xff;
57+
let mut data = vec![self.packet_id.fetch_add(1, Ordering::Relaxed), 0x02, 0x00, 0x05, 0x21, 0x05, 0x0e, speed as u8];
58+
let mut count = 1;
59+
for item in data.iter().skip(1) {
60+
sum -= item;
61+
count += 1;
62+
}
63+
sum += count;
64+
data.push(sum);
65+
66+
return Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, false).into()]);
67+
}
68+
}
69+
Ok(vec![])
70+
}
71+
72+
fn handle_scalar_vibrate_cmd(
73+
&self,
74+
_index: u32,
75+
scalar: u32,
76+
) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
77+
let mut sum: u8 = 0xff;
78+
let mut data = vec![self.packet_id.fetch_add(1, Ordering::Relaxed), 0x02, 0x00, 0x05, 0x21, 0x05, 0x08, scalar as u8];
79+
let mut count = 1;
80+
for item in data.iter().skip(1) {
81+
sum -= item;
82+
count += 1;
83+
}
84+
sum += count;
85+
data.push(sum);
86+
87+
Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, false).into()])
88+
}
89+
}

buttplug/tests/test_device_protocols.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ async fn load_test_case(test_file: &str) -> DeviceTestCase {
7575
#[test_case("test_hgod_protocol.yaml" ; "Hgod Protocol")]
7676
#[test_case("test_tryfun_protocol.yaml" ; "TryFun Protocol")]
7777
#[test_case("test_tryfun_surge.yaml" ; "TryFun Protocol - Surge Pro")]
78+
#[test_case("test_tryfun_meta2_protocol.yaml" ; "TryFun Protocol - Meta 2")]
79+
#[test_case("test_tryfun_blackhole_protocol.yaml" ; "TryFun Protocol - Black Hole Plus")]
7880
#[test_case("test_metaxsire_rex.yaml" ; "metaXsire Protocol - Rex")]
7981
#[test_case("test_metaxsire_olis.yaml" ; "metaXsire Protocol - Olis")]
8082
#[test_case("test_metaxsire_cali.yaml" ; "metaXsire Protocol - Cali")]
@@ -192,6 +194,8 @@ async fn test_device_protocols_embedded_v3(test_file: &str) {
192194
#[test_case("test_hgod_protocol.yaml" ; "Hgod Protocol")]
193195
#[test_case("test_tryfun_protocol.yaml" ; "TryFun Protocol")]
194196
#[test_case("test_tryfun_surge.yaml" ; "TryFun Protocol - Surge Pro")]
197+
#[test_case("test_tryfun_meta2_protocol.yaml" ; "TryFun Protocol - Meta 2")]
198+
#[test_case("test_tryfun_blackhole_protocol.yaml" ; "TryFun Protocol - Black Hole Plus")]
195199
#[test_case("test_metaxsire_rex.yaml" ; "metaXsire Protocol - Rex")]
196200
#[test_case("test_metaxsire_olis.yaml" ; "metaXsire Protocol - Olis")]
197201
#[test_case("test_metaxsire_cali.yaml" ; "metaXsire Protocol - Cali")]

0 commit comments

Comments
 (0)