12
12
import androidx .annotation .Nullable ;
13
13
import com .welie .blessed .BluetoothPeripheral ;
14
14
import com .welie .blessed .GattStatus ;
15
+ import com .welie .blessed .WriteType ;
15
16
import java .nio .ByteBuffer ;
16
17
import java .nio .ByteOrder ;
18
+ import java .util .Arrays ;
17
19
import java .util .UUID ;
18
20
19
21
public class Flysight2Protocol extends BleProtocol {
@@ -24,11 +26,15 @@ public class Flysight2Protocol extends BleProtocol {
24
26
private static final UUID flysightService0 = UUID .fromString ("00000000-cc7a-482a-984a-7f2ed5b3e58f" );
25
27
private static final UUID flysightService1 = UUID .fromString ("00000001-cc7a-482a-984a-7f2ed5b3e58f" );
26
28
private static final UUID flysightService2 = UUID .fromString ("00000002-cc7a-482a-984a-7f2ed5b3e58f" );
29
+
27
30
// Flysight characteristics
28
31
private static final UUID flysightCharacteristicGNSS = UUID .fromString ("00000000-8e22-4541-9d4c-21edae82ed19" );
29
32
private static final UUID flysightCharacteristicTX = UUID .fromString ("00000001-8e22-4541-9d4c-21edae82ed19" );
30
33
private static final UUID flysightCharacteristicRX = UUID .fromString ("00000002-8e22-4541-9d4c-21edae82ed19" );
31
34
35
+ // Flysight commands
36
+ private static final byte [] flysightCommandHeartbeat = new byte []{(byte ) 0xfe };
37
+
32
38
private static final long gpsEpochMilliseconds = 315964800000L - 18000L ; // January 6, 1980 - 18s
33
39
private static final long millisecondsPerWeek = 604800000L ;
34
40
@@ -46,6 +52,8 @@ public boolean canParse(@NonNull BluetoothPeripheral peripheral, @Nullable ScanR
46
52
public void onServicesDiscovered (@ NonNull BluetoothPeripheral peripheral ) {
47
53
Log .i (TAG , "flysight services discovered " + peripheral .getCurrentMtu ());
48
54
peripheral .requestMtu (256 );
55
+ // Start heartbeat thread
56
+ startHeartbeat (peripheral , flysightService0 , flysightCharacteristicRX );
49
57
}
50
58
51
59
@ Override
@@ -58,6 +66,10 @@ public void onMtuChanged(@NonNull BluetoothPeripheral peripheral, int mtu, @NonN
58
66
@ Override
59
67
public void processBytes (@ NonNull BluetoothPeripheral peripheral , @ NonNull byte [] value ) {
60
68
try {
69
+ // FlySight2 RC pre-2024-11-11 didn't have flag byte
70
+ if (value .length == 29 && value [0 ] == -80 ) { // 0xb0
71
+ value = Arrays .copyOfRange (value , 1 , value .length );
72
+ }
61
73
final ByteBuffer buf = ByteBuffer .wrap (value ).order (ByteOrder .LITTLE_ENDIAN );
62
74
final int tow = buf .getInt (0 ); // gps time of week
63
75
final double lng = buf .getInt (4 ) * 1e-7 ;
@@ -92,4 +104,23 @@ public void processBytes(@NonNull BluetoothPeripheral peripheral, @NonNull byte[
92
104
Exceptions .report (e );
93
105
}
94
106
}
107
+
108
+ private void startHeartbeat (@ NonNull BluetoothPeripheral peripheral , @ NonNull UUID service , @ NonNull UUID characteristic ) {
109
+ // Start heartbeat thread
110
+ new Thread (() -> {
111
+ try {
112
+ while (true ) {
113
+ // Send heartbeat every 14.5 seconds
114
+ if (peripheral .writeCharacteristic (service , characteristic , flysightCommandHeartbeat , WriteType .WITHOUT_RESPONSE )) {
115
+ Thread .sleep (14500 );
116
+ } else {
117
+ Log .w (TAG , "Failed to send heartbeat, stopping heartbeat thread" );
118
+ break ;
119
+ }
120
+ }
121
+ } catch (InterruptedException e ) {
122
+ Log .i (TAG , "Heartbeat thread interrupted" );
123
+ }
124
+ }).start ();
125
+ }
95
126
}
0 commit comments