1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Threading ;
5+ using System . Threading . Tasks ;
6+ using System . Timers ;
7+ using Buttplug . Core ;
8+ using Buttplug . Core . Messages ;
9+
10+ namespace Buttplug . Server . Bluetooth . Devices
11+ {
12+ internal class MysteryVibeBluetoothInfo : IBluetoothDeviceInfo
13+ {
14+ public enum Chrs : uint
15+ {
16+ ModeControl = 0 ,
17+ MotorControl = 1 ,
18+ }
19+
20+ public Guid [ ] Services { get ; } = { new Guid ( "f0006900-110c-478b-b74b-6f403b364a9c" ) } ;
21+
22+ public Dictionary < uint , Guid > Characteristics { get ; } = new Dictionary < uint , Guid > ( )
23+ {
24+ { ( uint ) Chrs . ModeControl , new Guid ( "f0006901-110c-478B-B74B-6F403B364A9C" ) } ,
25+ { ( uint ) Chrs . MotorControl , new Guid ( "f0006903-110c-478B-B74B-6F403B364A9C" ) } ,
26+ } ;
27+
28+ public string [ ] NamePrefixes { get ; } = { } ;
29+
30+ public string [ ] Names { get ; } =
31+ {
32+ "MV Crescendo" ,
33+ } ;
34+
35+ public IButtplugDevice CreateDevice ( IButtplugLogManager aLogManager ,
36+ IBluetoothDeviceInterface aInterface )
37+ {
38+ return new MysteryVibe ( aLogManager , aInterface , this ) ;
39+ }
40+ }
41+
42+ internal class MysteryVibe : ButtplugBluetoothDevice
43+ {
44+ internal static readonly byte [ ] NullSpeed = { 0 , 0 , 0 , 0 , 0 , 0 } ;
45+
46+ // This max speed seems weird, but going over it causes the device to slow down?
47+ internal static readonly byte MaxSpeed = 56 ;
48+
49+ // Approximate timing delay taken from watching packet timing and testing manually.
50+ internal static readonly uint DelayTimeMS = 93 ;
51+
52+ private byte [ ] _vibratorSpeeds = NullSpeed ;
53+ private readonly System . Timers . Timer _updateValueTimer = new System . Timers . Timer ( ) ;
54+
55+ public MysteryVibe ( IButtplugLogManager aLogManager ,
56+ IBluetoothDeviceInterface aInterface ,
57+ IBluetoothDeviceInfo aInfo )
58+ : base ( aLogManager ,
59+ $ "MysteryVibe Crescendo",
60+ aInterface ,
61+ aInfo )
62+ {
63+ // Create a new timer that wont fire any events just yet
64+
65+ _updateValueTimer . Interval = DelayTimeMS ;
66+ _updateValueTimer . Elapsed += MysteryVibeUpdateHandler ;
67+ _updateValueTimer . Enabled = false ;
68+ aInterface . DeviceRemoved += OnDeviceRemoved ;
69+
70+ MsgFuncs . Add ( typeof ( SingleMotorVibrateCmd ) , new ButtplugDeviceWrapper ( HandleSingleMotorVibrateCmd ) ) ;
71+ MsgFuncs . Add ( typeof ( VibrateCmd ) , new ButtplugDeviceWrapper ( HandleVibrateCmd , new MessageAttributes ( ) { FeatureCount = 6 } ) ) ;
72+ MsgFuncs . Add ( typeof ( StopDeviceCmd ) , new ButtplugDeviceWrapper ( HandleStopDeviceCmd ) ) ;
73+ }
74+
75+ public override async Task < ButtplugMessage > Initialize ( )
76+ {
77+ BpLogger . Trace ( $ "Initializing { Name } ") ;
78+
79+ // Kick Vibrator into motor control mode, just copying what the app sends when you go to
80+ // create pattern mode.
81+ return await Interface . WriteValue ( ButtplugConsts . SystemMsgId ,
82+ ( uint ) MysteryVibeBluetoothInfo . Chrs . ModeControl ,
83+ new byte [ ] { 0x43 , 0x02 , 0x00 } , true ) ;
84+ }
85+
86+ private void OnDeviceRemoved ( object aEvent , EventArgs aArgs )
87+ {
88+ // Timer should be turned off on removal.
89+ _updateValueTimer . Enabled = false ;
90+
91+ // Clean up event handler for that magic day when devices manage to disconnect.
92+ Interface . DeviceRemoved -= OnDeviceRemoved ;
93+ }
94+
95+ private async void MysteryVibeUpdateHandler ( object aEvent , ElapsedEventArgs aArgs )
96+ {
97+ if ( _vibratorSpeeds . SequenceEqual ( NullSpeed ) )
98+ {
99+ _updateValueTimer . Enabled = false ;
100+ }
101+
102+ if ( await Interface . WriteValue ( ButtplugConsts . DefaultMsgId ,
103+ ( uint ) MysteryVibeBluetoothInfo . Chrs . MotorControl ,
104+ _vibratorSpeeds ) is Error errorMsg )
105+ {
106+ BpLogger . Error ( $ "Cannot send update to { Name } , device may stop moving.") ;
107+ _updateValueTimer . Enabled = false ;
108+ }
109+ }
110+
111+ private async Task < ButtplugMessage > HandleStopDeviceCmd ( ButtplugDeviceMessage aMsg )
112+ {
113+ BpLogger . Debug ( $ "Stopping Device { Name } ") ;
114+ return await HandleSingleMotorVibrateCmd ( new SingleMotorVibrateCmd ( aMsg . DeviceIndex , 0 , aMsg . Id ) ) ;
115+ }
116+
117+ private async Task < ButtplugMessage > HandleSingleMotorVibrateCmd ( ButtplugDeviceMessage aMsg )
118+ {
119+ if ( ! ( aMsg is SingleMotorVibrateCmd cmdMsg ) )
120+ {
121+ return BpLogger . LogErrorMsg ( aMsg . Id , Error . ErrorClass . ERROR_DEVICE , "Wrong Handler" ) ;
122+ }
123+
124+ return await HandleVibrateCmd (
125+ VibrateCmd . Create ( cmdMsg . DeviceIndex , cmdMsg . Id , cmdMsg . Speed , 6 ) ) ;
126+ }
127+
128+ private async Task < ButtplugMessage > HandleVibrateCmd ( ButtplugDeviceMessage aMsg )
129+ {
130+ if ( ! ( aMsg is VibrateCmd cmdMsg ) )
131+ {
132+ return BpLogger . LogErrorMsg ( aMsg . Id , Error . ErrorClass . ERROR_DEVICE , "Wrong Handler" ) ;
133+ }
134+
135+ if ( cmdMsg . Speeds . Count < 1 || cmdMsg . Speeds . Count > 6 )
136+ {
137+ return new Error (
138+ "VibrateCmd requires 1-6 commands for this device." ,
139+ Error . ErrorClass . ERROR_DEVICE ,
140+ cmdMsg . Id ) ;
141+ }
142+
143+ var newVibratorSpeeds = ( byte [ ] ) _vibratorSpeeds . Clone ( ) ;
144+
145+ foreach ( var v in cmdMsg . Speeds )
146+ {
147+ if ( v . Index > 5 )
148+ {
149+ return new Error (
150+ $ "Index { v . Index } is out of bounds for VibrateCmd for this device.",
151+ Error . ErrorClass . ERROR_DEVICE ,
152+ cmdMsg . Id ) ;
153+ }
154+
155+ newVibratorSpeeds [ v . Index ] = ( byte ) ( v . Speed * MaxSpeed ) ;
156+ }
157+
158+ if ( newVibratorSpeeds . SequenceEqual ( _vibratorSpeeds ) )
159+ {
160+ return new Ok ( aMsg . Id ) ;
161+ }
162+
163+ _vibratorSpeeds = newVibratorSpeeds ;
164+
165+ if ( ! _updateValueTimer . Enabled )
166+ {
167+ // Run the update handler once to start the command
168+ MysteryVibeUpdateHandler ( null , null ) ;
169+
170+ // Start the timer to it will keep updating
171+ _updateValueTimer . Enabled = true ;
172+ }
173+
174+ return new Ok ( aMsg . Id ) ;
175+ }
176+ }
177+ }
0 commit comments