Skip to content

Commit d124eed

Browse files
blackspherefollowerqdot
authored andcommitted
feat: Onyx2 support
It turns out the protocol for the Onyx2 is identical to the Fleshlight Launch, with the exception that the handshake byte is written to the Cmd handle instead of the Tx. This adds the characteristic set to the existing Launch protocol class rather than duplicating it. Fixes #320
1 parent b1d0023 commit d124eed

4 files changed

Lines changed: 165 additions & 2 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System.Collections.Generic;
2+
using Buttplug.Core.Messages;
3+
using Buttplug.Server.Bluetooth.Devices;
4+
using Buttplug.Server.Test.Util;
5+
using JetBrains.Annotations;
6+
using NUnit.Framework;
7+
8+
namespace Buttplug.Server.Test.Bluetooth.Devices
9+
{
10+
[TestFixture]
11+
public class KiirooOnyx2Tests
12+
{
13+
[NotNull]
14+
private BluetoothDeviceTestUtils<KiirooOnyx2BluetoothInfo> testUtil;
15+
16+
[SetUp]
17+
public void Init()
18+
{
19+
testUtil = new BluetoothDeviceTestUtils<KiirooOnyx2BluetoothInfo>();
20+
testUtil.SetupTest("Onyx2");
21+
}
22+
23+
[Test]
24+
public void TestAllowedMessages()
25+
{
26+
testUtil.TestDeviceAllowedMessages(new Dictionary<System.Type, uint>()
27+
{
28+
{ typeof(StopDeviceCmd), 0 },
29+
{ typeof(FleshlightLaunchFW12Cmd), 0 },
30+
{ typeof(LinearCmd), 1 },
31+
});
32+
}
33+
34+
[Test]
35+
public void TestInitialize()
36+
{
37+
testUtil.TestDeviceInitialize(new List<(byte[], uint)>()
38+
{
39+
(new byte[1] { 0x0 }, (uint)KiirooOnyx2BluetoothInfo.Chrs.Cmd),
40+
}, true);
41+
}
42+
43+
// StopDeviceCmd test handled in GeneralDeviceTests
44+
45+
// In all device message tests, expect WriteWithResponse to be false.
46+
[Test]
47+
public void TestFleshlightLaunchFW12Cmd()
48+
{
49+
testUtil.TestDeviceMessage(new FleshlightLaunchFW12Cmd(4, 50, 50),
50+
new List<(byte[], uint)>()
51+
{
52+
(new byte[2] { 50, 50 }, (uint)KiirooOnyx2BluetoothInfo.Chrs.Tx),
53+
}, false);
54+
}
55+
56+
// TODO Test currently fails because we will send repeated packets to the launch. See #402.
57+
/*
58+
[Test]
59+
public void TestRepeatedFleshlightLaunchFW12Cmd()
60+
{
61+
testUtil.TestDeviceMessage(new FleshlightLaunchFW12Cmd(4, 50, 50),
62+
new List<byte[]>()
63+
{
64+
new byte[2] { 50, 50 },
65+
}, (uint)FleshlightLaunchBluetoothInfo.Chrs.Tx, false);
66+
testUtil.TestDeviceMessageNoop(new FleshlightLaunchFW12Cmd(4, 50, 50));
67+
}
68+
*/
69+
70+
[Test]
71+
public void TestVectorCmd()
72+
{
73+
var msg = new LinearCmd(4, new List<LinearCmd.VectorSubcommand>
74+
{
75+
new LinearCmd.VectorSubcommand(0, 500, 0.5),
76+
});
77+
testUtil.TestDeviceMessage(msg,
78+
new List<(byte[], uint)>()
79+
{
80+
(new byte[2] { 50, 20 }, (uint)KiirooOnyx2BluetoothInfo.Chrs.Tx),
81+
}, false);
82+
}
83+
84+
[Test]
85+
public void TestInvalidVectorCmdTooManyFeatures()
86+
{
87+
var msg = LinearCmd.Create(4, 0, 500, 0.75, 2);
88+
testUtil.TestInvalidDeviceMessage(msg);
89+
}
90+
91+
[Test]
92+
public void TestInvalidVectorCmdWrongFeatures()
93+
{
94+
var msg = new LinearCmd(4,
95+
new List<LinearCmd.VectorSubcommand>
96+
{
97+
new LinearCmd.VectorSubcommand(0xffffffff, 500, 0.75),
98+
});
99+
testUtil.TestInvalidDeviceMessage(msg);
100+
}
101+
102+
[Test]
103+
public void TestInvalidVectorNotEnoughFeatures()
104+
{
105+
var msg = LinearCmd.Create(4, 0, 500, 0.75, 0);
106+
testUtil.TestInvalidDeviceMessage(msg);
107+
}
108+
}
109+
}

Buttplug.Server.Test/Buttplug.Server.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
<ItemGroup>
6262
<Compile Include="ArgsTests.cs" />
6363
<Compile Include="AssemblyGitVersionTests.cs" />
64+
<Compile Include="Bluetooth\Devices\KiirooOnyx2Tests.cs" />
6465
<Compile Include="Bluetooth\Devices\FleshlightLaunchTests.cs" />
6566
<Compile Include="Bluetooth\Devices\GeneralDeviceTests.cs" />
6667
<Compile Include="Bluetooth\Devices\KiirooGen2VibeTests.cs" />

Buttplug.Server/Bluetooth/BluetoothSubtypeManager.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ protected BluetoothSubtypeManager([NotNull] IButtplugLogManager aLogManager)
2222
new FleshlightLaunchBluetoothInfo(),
2323
new KiirooBluetoothInfo(),
2424
new KiirooGen2VibeBluetoothInfo(),
25+
new KiirooOnyx2BluetoothInfo(),
2526
new YoucupsBluetoothInfo(),
2627
new LovenseBluetoothInfo(),
2728
new MagicMotionBluetoothInfo(),

Buttplug.Server/Bluetooth/Devices/FleshlightLaunch.cs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,63 @@ public IButtplugDevice CreateDevice(
4343
}
4444
}
4545

46+
internal class KiirooOnyx2BluetoothInfo : IBluetoothDeviceInfo
47+
{
48+
public enum Chrs : uint
49+
{
50+
Tx = 0,
51+
Rx,
52+
Cmd,
53+
}
54+
55+
public string[] Names { get; } = { "Onyx2" };
56+
57+
public string[] NamePrefixes { get; } = { };
58+
59+
public Guid[] Services { get; } = { new Guid("f60402a6-0293-4bdb-9f20-6758133f7090") };
60+
61+
public Dictionary<uint, Guid> Characteristics { get; } = new Dictionary<uint, Guid>
62+
{
63+
// Tx
64+
{ (uint)Chrs.Tx, new Guid("02962ac9-e86f-4094-989d-231d69995fc2") },
65+
66+
// Rx
67+
{ (uint)Chrs.Rx, new Guid("d44d0393-0731-43b3-a373-8fc70b1f3323") },
68+
69+
// Cmd
70+
{ (uint)Chrs.Cmd, new Guid("c7b7a04b-2cc4-40ff-8b10-5d531d1161db") },
71+
};
72+
73+
public IButtplugDevice CreateDevice(IButtplugLogManager aLogManager,
74+
IBluetoothDeviceInterface aInterface)
75+
{
76+
return new FleshlightLaunch(aLogManager, aInterface, this);
77+
}
78+
}
79+
4680
internal class FleshlightLaunch : ButtplugBluetoothDevice
4781
{
82+
private static Dictionary<string, string> _brandNames = new Dictionary<string, string>
83+
{
84+
{ "Launch", "Fleshlight" },
85+
{ "Onyx2", "Kiiroo" },
86+
};
87+
4888
private double _lastPosition;
4989

5090
public FleshlightLaunch([NotNull] IButtplugLogManager aLogManager,
5191
[NotNull] IBluetoothDeviceInterface aInterface,
5292
[NotNull] IBluetoothDeviceInfo aInfo)
5393
: base(aLogManager,
54-
"Fleshlight Launch",
94+
aInterface.Name,
5595
aInterface,
5696
aInfo)
5797
{
98+
if (_brandNames.ContainsKey(aInterface.Name))
99+
{
100+
Name = $"{_brandNames[aInterface.Name]} {aInterface.Name}";
101+
}
102+
58103
// Setup message function array
59104
MsgFuncs.Add(typeof(FleshlightLaunchFW12Cmd), new ButtplugDeviceWrapper(HandleFleshlightLaunchRawCmd));
60105
MsgFuncs.Add(typeof(LinearCmd), new ButtplugDeviceWrapper(HandleLinearCmd, new MessageAttributes() { FeatureCount = 1 }));
@@ -64,8 +109,15 @@ public FleshlightLaunch([NotNull] IButtplugLogManager aLogManager,
64109
public override async Task<ButtplugMessage> Initialize()
65110
{
66111
BpLogger.Trace($"Initializing {Name}");
112+
var chr = (uint)FleshlightLaunchBluetoothInfo.Chrs.Tx;
113+
114+
if (Name == "Kiiroo Onyx2")
115+
{
116+
chr = (uint)KiirooOnyx2BluetoothInfo.Chrs.Cmd;
117+
}
118+
67119
return await Interface.WriteValue(ButtplugConsts.SystemMsgId,
68-
(int)FleshlightLaunchBluetoothInfo.Chrs.Tx,
120+
chr,
69121
new byte[] { 0 },
70122
true);
71123
}

0 commit comments

Comments
 (0)