1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-09 19:49:30 +01:00

Improve BLE gatt handling

- close() the gatt instance when explicitly disconnecting
- create a new gatt instance when explicitly connecting

Unfortunately I still appear to get spontaneous disconnects after some
notifications.
This commit is contained in:
cpfeiffer 2015-05-22 23:15:45 +02:00
parent f54927624b
commit 880dc7b3a4
2 changed files with 64 additions and 9 deletions

View File

@ -49,6 +49,7 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im
public void dispose() { public void dispose() {
if (mQueue != null) { if (mQueue != null) {
mQueue.dispose(); mQueue.dispose();
mQueue = null;
} }
} }

View File

@ -28,6 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBDevice.State;
public final class BtLEQueue { public final class BtLEQueue {
private static final Logger LOG = LoggerFactory.getLogger(BtLEQueue.class); private static final Logger LOG = LoggerFactory.getLogger(BtLEQueue.class);
private Object mGattMonitor = new Object();
private GBDevice mGbDevice; private GBDevice mGbDevice;
private BluetoothAdapter mBluetoothAdapter; private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt; private BluetoothGatt mBluetoothGatt;
@ -127,10 +128,21 @@ public final class BtLEQueue {
LOG.warn("Ingoring connect() because already connected."); LOG.warn("Ingoring connect() because already connected.");
return false; return false;
} }
synchronized (mGattMonitor) {
if (mBluetoothGatt != null) {
// Tribal knowledge says you're better off not reusing existing BlueoothGatt connections,
// so create a new one.
LOG.info("connect() requested -- disconnecting previous connection: " + mGbDevice.getName());
disconnect();
}
}
LOG.info("Attempting to connect to " + mGbDevice.getName()); LOG.info("Attempting to connect to " + mGbDevice.getName());
BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(mGbDevice.getAddress()); BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(mGbDevice.getAddress());
mBluetoothGatt = remoteDevice.connectGatt(mContext, false, internalGattCallback); boolean result = false;
boolean result = mBluetoothGatt.connect(); synchronized (mGattMonitor) {
mBluetoothGatt = remoteDevice.connectGatt(mContext, false, internalGattCallback);
result = mBluetoothGatt.connect();
}
setDeviceConnectionState(result ? State.CONNECTING : State.NOT_CONNECTED); setDeviceConnectionState(result ? State.CONNECTING : State.NOT_CONNECTED);
return result; return result;
} }
@ -144,11 +156,13 @@ public final class BtLEQueue {
} }
public void disconnect() { public void disconnect() {
if (mBluetoothGatt != null) { synchronized (mGattMonitor) {
LOG.info("Disconnecting BtLEQueue from GATT device"); if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect(); LOG.info("Disconnecting BtLEQueue from GATT device");
mBluetoothGatt.close(); mBluetoothGatt.disconnect();
mBluetoothGatt = null; mBluetoothGatt.close();
mBluetoothGatt = null;
}
} }
} }
@ -158,6 +172,10 @@ public final class BtLEQueue {
mWaitForActionResultLatch.countDown(); mWaitForActionResultLatch.countDown();
} }
setDeviceConnectionState(State.NOT_CONNECTED); setDeviceConnectionState(State.NOT_CONNECTED);
// either we've been disconnected because the device is out of range
// or because of an explicit @{link #disconnect())
// To support automatic reconnection, we keep the mBluetoothGatt instance
// alive (we do not close() it).
} }
public void dispose() { public void dispose() {
@ -206,11 +224,23 @@ public final class BtLEQueue {
return mBluetoothGatt.getServices(); return mBluetoothGatt.getServices();
} }
private boolean checkCorrectGattInstance(BluetoothGatt gatt, String where) {
if (gatt != mBluetoothGatt) {
LOG.info("Ignoring event from wrong BluetoothGatt instance: " + where);
return false;
}
return true;
}
// Implements callback methods for GATT events that the app cares about. For example, // Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered. // connection change and services discovered.
private final BluetoothGattCallback internalGattCallback = new BluetoothGattCallback() { private final BluetoothGattCallback internalGattCallback = new BluetoothGattCallback() {
@Override @Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (!checkCorrectGattInstance(gatt, "connection state event")) {
return;
}
switch (newState) { switch (newState) {
case BluetoothProfile.STATE_CONNECTED: case BluetoothProfile.STATE_CONNECTED:
LOG.info("Connected to GATT server."); LOG.info("Connected to GATT server.");
@ -232,6 +262,10 @@ public final class BtLEQueue {
@Override @Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) { public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (!checkCorrectGattInstance(gatt, "services discovered")) {
return;
}
if (status == BluetoothGatt.GATT_SUCCESS) { if (status == BluetoothGatt.GATT_SUCCESS) {
if (mExternalGattCallback != null) { if (mExternalGattCallback != null) {
// only propagate the successful event // only propagate the successful event
@ -244,10 +278,13 @@ public final class BtLEQueue {
@Override @Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (!checkCorrectGattInstance(gatt, "characteristic write")) {
return;
}
if (status == BluetoothGatt.GATT_SUCCESS) { if (status == BluetoothGatt.GATT_SUCCESS) {
LOG.info("Writing characteristic " + characteristic.getUuid() + " succeeded."); LOG.debug("Writing characteristic " + characteristic.getUuid() + " succeeded.");
} else { } else {
LOG.error("Writing characteristic " + characteristic.getUuid() + " failed: " + status); LOG.debug("Writing characteristic " + characteristic.getUuid() + " failed: " + status);
} }
if (mExternalGattCallback != null) { if (mExternalGattCallback != null) {
mExternalGattCallback.onCharacteristicWrite(gatt, characteristic, status); mExternalGattCallback.onCharacteristicWrite(gatt, characteristic, status);
@ -259,6 +296,9 @@ public final class BtLEQueue {
public void onCharacteristicRead(BluetoothGatt gatt, public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, BluetoothGattCharacteristic characteristic,
int status) { int status) {
if (!checkCorrectGattInstance(gatt, "characteristic read")) {
return;
}
if (status != BluetoothGatt.GATT_SUCCESS) { if (status != BluetoothGatt.GATT_SUCCESS) {
LOG.error("Reading characteristic " + characteristic.getUuid() + " failed: " + status); LOG.error("Reading characteristic " + characteristic.getUuid() + " failed: " + status);
} }
@ -271,6 +311,13 @@ public final class BtLEQueue {
@Override @Override
public void onCharacteristicChanged(BluetoothGatt gatt, public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) { BluetoothGattCharacteristic characteristic) {
if (!checkCorrectGattInstance(gatt, "characteristic changed")) {
return;
}
if (gatt != mBluetoothGatt) {
LOG.info("Ignoring characteristic change event from wrong BluetoothGatt instance");
return;
}
if (mExternalGattCallback != null) { if (mExternalGattCallback != null) {
mExternalGattCallback.onCharacteristicChanged(gatt, characteristic); mExternalGattCallback.onCharacteristicChanged(gatt, characteristic);
} }
@ -278,6 +325,13 @@ public final class BtLEQueue {
@Override @Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
if (!checkCorrectGattInstance(gatt, "remote rssi")) {
return;
}
if (gatt != mBluetoothGatt) {
LOG.info("Ignoring remote rssi event from wrong BluetoothGatt instance");
return;
}
if (mExternalGattCallback != null) { if (mExternalGattCallback != null) {
mExternalGattCallback.onReadRemoteRssi(gatt, rssi, status); mExternalGattCallback.onReadRemoteRssi(gatt, rssi, status);
} }