diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTClient.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTClient.java index 830626917..e8df7511f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTClient.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTClient.java @@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory; import java.lang.reflect.Method; import java.util.UUID; +import java.util.concurrent.CountDownLatch; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -62,6 +63,8 @@ class PebbleGATTClient extends BluetoothGattCallback { private boolean removeBond = false; private BluetoothGatt mBluetoothGatt; + private CountDownLatch mWaitWriteCompleteLatch; + PebbleGATTClient(PebbleLESupport pebbleLESupport, Context context, BluetoothDevice btDevice) { mContext = context; mPebbleLESupport = pebbleLESupport; @@ -119,9 +122,16 @@ class PebbleGATTClient extends BluetoothGattCallback { if (!mPebbleLESupport.isExpectedDevice(gatt.getDevice())) { return; } - - LOG.info("onCharacteristicWrite() " + characteristic.getUuid()); - if (characteristic.getUuid().equals(PAIRING_TRIGGER_CHARACTERISTIC) || characteristic.getUuid().equals(CONNECTIVITY_CHARACTERISTIC)) { + if (characteristic.getUuid().equals(PPOGATT_CHARACTERISTIC_WRITE)) { + if (status != BluetoothGatt.GATT_SUCCESS) { + LOG.error("something went wrong when writing to PPoGATT characteristics"); + } + if (mWaitWriteCompleteLatch != null) { + mWaitWriteCompleteLatch.countDown(); + } else { + LOG.warn("mWaitWriteCompleteLatch is null!"); + } + } else if (characteristic.getUuid().equals(PAIRING_TRIGGER_CHARACTERISTIC) || characteristic.getUuid().equals(CONNECTIVITY_CHARACTERISTIC)) { //mBtDevice.createBond(); // did not work when last tried if (oldPebble) { @@ -266,13 +276,20 @@ class PebbleGATTClient extends BluetoothGattCallback { } synchronized void sendDataToPebble(byte[] data) { + mWaitWriteCompleteLatch = new CountDownLatch(1); writeCharacteristics.setValue(data.clone()); - mBluetoothGatt.writeCharacteristic(writeCharacteristics); - } - synchronized void sendAckToPebble(int serial) { - writeCharacteristics.setValue(new byte[]{(byte) (((serial << 3) | 1) & 0xff)}); - mBluetoothGatt.writeCharacteristic(writeCharacteristics); + boolean success = mBluetoothGatt.writeCharacteristic(writeCharacteristics); + if (!success) { + LOG.error("could not send data to pebble (error writing characteristic)"); + } else { + try { + mWaitWriteCompleteLatch.await(); + } catch (InterruptedException e) { + LOG.warn("interrupted while waiting for write complete latch"); + } + } + mWaitWriteCompleteLatch = null; } public void close() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTServer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTServer.java index 9edb87717..aaa410278 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTServer.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTServer.java @@ -52,7 +52,9 @@ class PebbleGATTServer extends BluetoothGattServerCallback { boolean initialize() { BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE); - + if (bluetoothManager == null) { + return false; + } mBluetoothGattServer = bluetoothManager.openGattServer(mContext, this); if (mBluetoothGattServer == null) { return false; @@ -76,12 +78,6 @@ class PebbleGATTServer extends BluetoothGattServerCallback { mBluetoothGattServer.notifyCharacteristicChanged(mBtDevice, writeCharacteristics, false); } - synchronized void sendAckToPebble(int serial) { - writeCharacteristics.setValue(new byte[]{(byte) (((serial << 3) | 1) & 0xff)}); - - mBluetoothGattServer.notifyCharacteristicChanged(mBtDevice, writeCharacteristics, false); - } - public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { if (!mPebbleLESupport.isExpectedDevice(device)) { return; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java index 610f08788..2eb0c1aff 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java @@ -18,6 +18,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.ble; import android.bluetooth.BluetoothDevice; import android.content.Context; +import android.os.Handler; +import android.os.HandlerThread; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,9 +41,11 @@ public class PebbleLESupport { private PipedOutputStream mPipedOutputStream; private int mMTU = 20; private int mMTULimit = Integer.MAX_VALUE; - public boolean clientOnly = false; // currently broken, and only possible for Pebble 2 + public boolean clientOnly = false; // currently experimental, and only possible for Pebble 2 private boolean mIsConnected = false; private CountDownLatch mPPAck; + private HandlerThread mWriteHandlerThread; + private Handler mWriteHandler; public PebbleLESupport(Context context, final BluetoothDevice btDevice, PipedInputStream pipedInputStream, PipedOutputStream pipedOutputStream) throws IOException { mBtDevice = btDevice; @@ -53,6 +57,11 @@ public class PebbleLESupport { } catch (IOException e) { LOG.warn("could not connect input stream"); } + + mWriteHandlerThread = new HandlerThread("write handler thread"); + mWriteHandlerThread.start(); + mWriteHandler = new Handler(mWriteHandlerThread.getLooper()); + mMTULimit = GBApplication.getPrefs().getInt("pebble_mtu_limit", 512); mMTULimit = Math.max(mMTULimit, 20); mMTULimit = Math.min(mMTULimit, 512); @@ -102,6 +111,9 @@ public class PebbleLESupport { mPipedOutputStream.close(); } catch (IOException ignore) { } + if (mWriteHandlerThread != null) { + mWriteHandlerThread.quit(); + } } private synchronized void createPipedInputReader() { @@ -166,18 +178,20 @@ public class PebbleLESupport { } private void sendAckToPebble(int serial) { - if (mPebbleGATTServer != null) { - mPebbleGATTServer.sendAckToPebble(serial); - } else { - mPebbleGATTClient.sendAckToPebble(serial); - } + sendDataToPebble(new byte[]{(byte) (((serial << 3) | 1) & 0xff)}); } - private void sendDataToPebble(byte[] bytes) { + private synchronized void sendDataToPebble(final byte[] bytes) { if (mPebbleGATTServer != null) { mPebbleGATTServer.sendDataToPebble(bytes); } else { - mPebbleGATTClient.sendDataToPebble(bytes); + // For now only in experimental client only code + mWriteHandler.post(new Runnable() { + @Override + public void run() { + mPebbleGATTClient.sendDataToPebble(bytes); + } + }); } }