1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-24 09:13:04 +02:00

Try to run all ble commands on the main thread

This commit is contained in:
Erik Johansson
2018-10-07 22:26:40 +02:00
parent c381f48aa9
commit 8d47f9b968

View File

@@ -80,7 +80,6 @@ public abstract class BluetoothCommunication {
private Queue<GattObjectValue<BluetoothGattDescriptor>> descriptorRequestQueue; private Queue<GattObjectValue<BluetoothGattDescriptor>> descriptorRequestQueue;
private Queue<GattObjectValue<BluetoothGattCharacteristic>> characteristicRequestQueue; private Queue<GattObjectValue<BluetoothGattCharacteristic>> characteristicRequestQueue;
private boolean openRequest; private boolean openRequest;
private final Object lock = new Object();
public BluetoothCommunication(Context context) public BluetoothCommunication(Context context)
{ {
@@ -240,11 +239,9 @@ public abstract class BluetoothCommunication {
* @param btMachineState the machine state that should be set. * @param btMachineState the machine state that should be set.
*/ */
protected void setBtMachineState(BT_MACHINE_STATE btMachineState) { protected void setBtMachineState(BT_MACHINE_STATE btMachineState) {
synchronized (lock) {
this.btMachineState = btMachineState; this.btMachineState = btMachineState;
handleRequests(); handleRequests();
} }
}
/** /**
* Write a byte array to a Bluetooth device. * Write a byte array to a Bluetooth device.
@@ -254,14 +251,12 @@ public abstract class BluetoothCommunication {
* @param bytes the bytes that should be write * @param bytes the bytes that should be write
*/ */
protected void writeBytes(UUID service, UUID characteristic, byte[] bytes) { protected void writeBytes(UUID service, UUID characteristic, byte[] bytes) {
synchronized (lock) {
characteristicRequestQueue.add( characteristicRequestQueue.add(
new GattObjectValue<>( new GattObjectValue<>(
bluetoothGatt.getService(service).getCharacteristic(characteristic), bluetoothGatt.getService(service).getCharacteristic(characteristic),
bytes)); bytes));
handleRequests(); handleRequests();
} }
}
/** /**
* Read bytes from a Bluetooth device. * Read bytes from a Bluetooth device.
@@ -301,14 +296,12 @@ public abstract class BluetoothCommunication {
bluetoothGatt.getService(service).getCharacteristic(characteristic); bluetoothGatt.getService(service).getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true); bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
synchronized (lock) {
descriptorRequestQueue.add( descriptorRequestQueue.add(
new GattObjectValue<>( new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor), gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)); BluetoothGattDescriptor.ENABLE_INDICATION_VALUE));
handleRequests(); handleRequests();
} }
}
catch (Exception e) { catch (Exception e) {
Timber.e(e); Timber.e(e);
} }
@@ -328,14 +321,12 @@ public abstract class BluetoothCommunication {
bluetoothGatt.getService(service).getCharacteristic(characteristic); bluetoothGatt.getService(service).getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true); bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
synchronized (lock) {
descriptorRequestQueue.add( descriptorRequestQueue.add(
new GattObjectValue<>( new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor), gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)); BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE));
handleRequests(); handleRequests();
} }
}
catch (Exception e) { catch (Exception e) {
Timber.e(e); Timber.e(e);
} }
@@ -354,14 +345,12 @@ public abstract class BluetoothCommunication {
bluetoothGatt.getService(service).getCharacteristic(characteristic); bluetoothGatt.getService(service).getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, false); bluetoothGatt.setCharacteristicNotification(gattCharacteristic, false);
synchronized (lock) {
descriptorRequestQueue.add( descriptorRequestQueue.add(
new GattObjectValue<>( new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor), gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)); BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE));
handleRequests(); handleRequests();
} }
}
/** /**
* Convert a byte array to hex for debugging purpose * Convert a byte array to hex for debugging purpose
@@ -415,6 +404,8 @@ public abstract class BluetoothCommunication {
* @param hwAddress the Bluetooth address to connect to * @param hwAddress the Bluetooth address to connect to
*/ */
public void connect(String hwAddress) { public void connect(String hwAddress) {
disconnect(false);
logBluetoothStatus(); logBluetoothStatus();
// Some good tips to improve BLE connections: // Some good tips to improve BLE connections:
@@ -481,6 +472,7 @@ public abstract class BluetoothCommunication {
if (!device.getAddress().equals(hwAddress)) { if (!device.getAddress().equals(hwAddress)) {
return; return;
} }
// Stop scan and connect to the device on the main thread
handler.post(new Runnable() { handler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -496,15 +488,14 @@ public abstract class BluetoothCommunication {
Timber.d("Starting LE scan for device [%s]", hwAddress); Timber.d("Starting LE scan for device [%s]", hwAddress);
btAdapter.startLeScan(leScanCallback); btAdapter.startLeScan(leScanCallback);
// Stop scan and try to connect to the device directly if the device isn't found in time
handler.postAtTime(new Runnable() { handler.postAtTime(new Runnable() {
@Override @Override
public void run() { public void run() {
Timber.d("Device not found in LE scan, connecting directly"); Timber.d("Device not found in LE scan, connecting directly");
synchronized (lock) {
stopLeScan(); stopLeScan();
connectGatt(hwAddress); connectGatt(hwAddress);
} }
}
}, leScanCallback, SystemClock.uptimeMillis() + LE_SCAN_TIMEOUT_MS); }, leScanCallback, SystemClock.uptimeMillis() + LE_SCAN_TIMEOUT_MS);
} }
@@ -521,7 +512,6 @@ public abstract class BluetoothCommunication {
* Disconnect from a Bluetooth device * Disconnect from a Bluetooth device
*/ */
public void disconnect(boolean doCleanup) { public void disconnect(boolean doCleanup) {
synchronized (lock) {
stopLeScan(); stopLeScan();
if (bluetoothGatt == null) { if (bluetoothGatt == null) {
@@ -530,9 +520,6 @@ public abstract class BluetoothCommunication {
Timber.i("Disconnecting%s", doCleanup ? " (with cleanup)" : ""); Timber.i("Disconnecting%s", doCleanup ? " (with cleanup)" : "");
handler.removeCallbacksAndMessages(null);
callbackBtHandler = null;
if (doCleanup) { if (doCleanup) {
if (btMachineState != BT_MACHINE_STATE.BT_CLEANUP_STATE) { if (btMachineState != BT_MACHINE_STATE.BT_CLEANUP_STATE) {
setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE); setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE);
@@ -541,13 +528,12 @@ public abstract class BluetoothCommunication {
handler.post(new Runnable() { handler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
synchronized (lock) {
if (openRequest) { if (openRequest) {
handler.postDelayed(this, 10); handler.postDelayed(this, 10);
} else { } else {
bluetoothGatt.close(); bluetoothGatt.close();
bluetoothGatt = null; bluetoothGatt = null;
} handler.removeCallbacksAndMessages(null);
} }
} }
}); });
@@ -556,7 +542,9 @@ public abstract class BluetoothCommunication {
bluetoothGatt.close(); bluetoothGatt.close();
bluetoothGatt = null; bluetoothGatt = null;
} }
}
handler.removeCallbacksAndMessages(null);
callbackBtHandler = null;
} }
/** /**
@@ -586,7 +574,6 @@ public abstract class BluetoothCommunication {
} }
private void handleRequests() { private void handleRequests() {
synchronized (lock) {
// check for pending request // check for pending request
if (openRequest) { if (openRequest) {
Timber.d("Request pending (queue %d %d)", Timber.d("Request pending (queue %d %d)",
@@ -615,8 +602,9 @@ public abstract class BluetoothCommunication {
if (characteristic != null) { if (characteristic != null) {
characteristic.gattObject.setValue(characteristic.value); characteristic.gattObject.setValue(characteristic.value);
Timber.d("Write characteristic %s: %s (queue: %d %d)", Timber.d("Write characteristic %s: %s (type: %d; queue: %d %d)",
characteristic.gattObject.getUuid(), byteInHex(characteristic.gattObject.getValue()), characteristic.gattObject.getUuid(), byteInHex(characteristic.gattObject.getValue()),
characteristic.gattObject.getWriteType(),
descriptorRequestQueue.size(), characteristicRequestQueue.size()); descriptorRequestQueue.size(), characteristicRequestQueue.size());
if (!bluetoothGatt.writeCharacteristic(characteristic.gattObject)) { if (!bluetoothGatt.writeCharacteristic(characteristic.gattObject)) {
Timber.e("Failed to initiate write of characteristic %s", Timber.e("Failed to initiate write of characteristic %s",
@@ -629,7 +617,6 @@ public abstract class BluetoothCommunication {
// After every command was executed, continue with the next step // After every command was executed, continue with the next step
nextMachineStateStep(); nextMachineStateStep();
} }
}
/** /**
* Custom Gatt callback class to set up a Bluetooth state machine. * Custom Gatt callback class to set up a Bluetooth state machine.
@@ -640,9 +627,10 @@ public abstract class BluetoothCommunication {
Timber.d("onConnectionStateChange: status=%d, newState=%d", status, newState); Timber.d("onConnectionStateChange: status=%d, newState=%d", status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) { if (newState == BluetoothProfile.STATE_CONNECTED) {
synchronized (lock) { handler.post(new Runnable() {
@Override
public void run() {
stopLeScan(); stopLeScan();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
gatt.readPhy(); gatt.readPhy();
@@ -650,25 +638,32 @@ public abstract class BluetoothCommunication {
connectionEstablished = true; connectionEstablished = true;
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED); setBtStatus(BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED);
}
});
try { // Wait a short while after connecting before scanning for services
Thread.sleep(1000); handler.postDelayed(new Runnable() {
} @Override
catch (Exception e) { public void run() {
// Empty
}
if (!gatt.discoverServices()) { if (!gatt.discoverServices()) {
Timber.e("Could not start service discovery"); Timber.e("Could not start service discovery");
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST); setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST);
disconnect(false); disconnect(false);
} }
} }
}, 1000);
}
else if (newState == BluetoothProfile.STATE_DISCONNECTED) { else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
handler.post(new Runnable() {
@Override
public void run() {
setBtStatus(connectionEstablished setBtStatus(connectionEstablished
? BT_STATUS_CODE.BT_CONNECTION_LOST ? BT_STATUS_CODE.BT_CONNECTION_LOST
: BT_STATUS_CODE.BT_NO_DEVICE_FOUND); : BT_STATUS_CODE.BT_NO_DEVICE_FOUND);
disconnect(false); disconnect(false);
} }
});
}
} }
@Override @Override
@@ -677,12 +672,22 @@ public abstract class BluetoothCommunication {
status, gatt.getServices().size()); status, gatt.getServices().size());
if (gatt.getServices().isEmpty()) { if (gatt.getServices().isEmpty()) {
handler.post(new Runnable() {
@Override
public void run() {
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "No services found"); setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "No services found");
disconnect(false); disconnect(false);
}
});
return; return;
} }
synchronized (lock) { // Sleeping a while after discovering services fixes connection problems.
// See https://github.com/NordicSemiconductor/Android-DFU-Library/issues/10
// for some technical background.
handler.postDelayed(new Runnable() {
@Override
public void run() {
cmdStepNr = 0; cmdStepNr = 0;
initStepNr = 0; initStepNr = 0;
cleanupStepNr = 0; cleanupStepNr = 0;
@@ -691,21 +696,12 @@ public abstract class BluetoothCommunication {
characteristicRequestQueue = new LinkedList<>(); characteristicRequestQueue = new LinkedList<>();
descriptorRequestQueue = new LinkedList<>(); descriptorRequestQueue = new LinkedList<>();
openRequest = false; openRequest = false;
}
try {
// Sleeping a while after discovering services fixes connection problems.
// See https://github.com/NordicSemiconductor/Android-DFU-Library/issues/10
// for some technical background.
Thread.sleep(1000);
}
catch (Exception e) {
// Empty
}
// Start the state machine // Start the state machine
setBtMachineState(BT_MACHINE_STATE.BT_INIT_STATE); setBtMachineState(BT_MACHINE_STATE.BT_INIT_STATE);
} }
}, 1000);
}
@Override @Override
public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) { public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
@@ -723,11 +719,9 @@ public abstract class BluetoothCommunication {
handler.postDelayed(new Runnable() { handler.postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
synchronized (lock) {
openRequest = false; openRequest = false;
handleRequests(); handleRequests();
} }
}
}, 60); }, 60);
} }
@@ -746,27 +740,33 @@ public abstract class BluetoothCommunication {
} }
@Override @Override
public void onCharacteristicRead(BluetoothGatt gatt, public void onCharacteristicRead(final BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, final BluetoothGattCharacteristic characteristic,
int status) { final int status) {
Timber.d("onCharacteristicRead %s (status=%d): %s", Timber.d("onCharacteristicRead %s (status=%d): %s",
characteristic.getUuid(), status, byteInHex(characteristic.getValue())); characteristic.getUuid(), status, byteInHex(characteristic.getValue()));
synchronized (lock) { handler.post(new Runnable() {
@Override
public void run() {
onBluetoothDataRead(gatt, characteristic, status); onBluetoothDataRead(gatt, characteristic, status);
postDelayedHandleRequests();
} }
});
postDelayedHandleRequests();
} }
@Override @Override
public void onCharacteristicChanged(BluetoothGatt gatt, public void onCharacteristicChanged(final BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) { final BluetoothGattCharacteristic characteristic) {
Timber.d("onCharacteristicChanged %s: %s", Timber.d("onCharacteristicChanged %s: %s",
characteristic.getUuid(), byteInHex(characteristic.getValue())); characteristic.getUuid(), byteInHex(characteristic.getValue()));
synchronized (lock) { handler.post(new Runnable() {
@Override
public void run() {
onBluetoothDataChange(gatt, characteristic); onBluetoothDataChange(gatt, characteristic);
} }
});
} }
@Override @Override