1212import androidx .annotation .Nullable ;
1313import com .welie .blessed .BluetoothPeripheral ;
1414import com .welie .blessed .GattStatus ;
15+ import com .welie .blessed .WriteType ;
1516import java .nio .ByteBuffer ;
1617import java .nio .ByteOrder ;
18+ import java .util .Arrays ;
1719import java .util .UUID ;
1820
1921public class Flysight2Protocol extends BleProtocol {
@@ -24,11 +26,15 @@ public class Flysight2Protocol extends BleProtocol {
2426 private static final UUID flysightService0 = UUID .fromString ("00000000-cc7a-482a-984a-7f2ed5b3e58f" );
2527 private static final UUID flysightService1 = UUID .fromString ("00000001-cc7a-482a-984a-7f2ed5b3e58f" );
2628 private static final UUID flysightService2 = UUID .fromString ("00000002-cc7a-482a-984a-7f2ed5b3e58f" );
29+
2730 // Flysight characteristics
2831 private static final UUID flysightCharacteristicGNSS = UUID .fromString ("00000000-8e22-4541-9d4c-21edae82ed19" );
2932 private static final UUID flysightCharacteristicTX = UUID .fromString ("00000001-8e22-4541-9d4c-21edae82ed19" );
3033 private static final UUID flysightCharacteristicRX = UUID .fromString ("00000002-8e22-4541-9d4c-21edae82ed19" );
3134
35+ // Flysight commands
36+ private static final byte [] flysightCommandHeartbeat = new byte []{(byte ) 0xfe };
37+
3238 private static final long gpsEpochMilliseconds = 315964800000L - 18000L ; // January 6, 1980 - 18s
3339 private static final long millisecondsPerWeek = 604800000L ;
3440
@@ -46,6 +52,8 @@ public boolean canParse(@NonNull BluetoothPeripheral peripheral, @Nullable ScanR
4652 public void onServicesDiscovered (@ NonNull BluetoothPeripheral peripheral ) {
4753 Log .i (TAG , "flysight services discovered " + peripheral .getCurrentMtu ());
4854 peripheral .requestMtu (256 );
55+ // Start heartbeat thread
56+ startHeartbeat (peripheral , flysightService0 , flysightCharacteristicRX );
4957 }
5058
5159 @ Override
@@ -58,6 +66,10 @@ public void onMtuChanged(@NonNull BluetoothPeripheral peripheral, int mtu, @NonN
5866 @ Override
5967 public void processBytes (@ NonNull BluetoothPeripheral peripheral , @ NonNull byte [] value ) {
6068 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+ }
6173 final ByteBuffer buf = ByteBuffer .wrap (value ).order (ByteOrder .LITTLE_ENDIAN );
6274 final int tow = buf .getInt (0 ); // gps time of week
6375 final double lng = buf .getInt (4 ) * 1e-7 ;
@@ -92,4 +104,23 @@ public void processBytes(@NonNull BluetoothPeripheral peripheral, @NonNull byte[
92104 Exceptions .report (e );
93105 }
94106 }
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+ }
95126}
0 commit comments