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,10 +239,8 @@ 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();
}
} }
/** /**
@@ -254,13 +251,11 @@ 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();
}
} }
/** /**
@@ -301,13 +296,11 @@ 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,13 +321,11 @@ 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,13 +345,11 @@ 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();
}
} }
/** /**
@@ -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,14 +488,13 @@ 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,42 +512,39 @@ 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) {
return; return;
}
Timber.i("Disconnecting%s", doCleanup ? " (with cleanup)" : "");
handler.removeCallbacksAndMessages(null);
callbackBtHandler = null;
if (doCleanup) {
if (btMachineState != BT_MACHINE_STATE.BT_CLEANUP_STATE) {
setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE);
nextMachineStateStep();
}
handler.post(new Runnable() {
@Override
public void run() {
synchronized (lock) {
if (openRequest) {
handler.postDelayed(this, 10);
} else {
bluetoothGatt.close();
bluetoothGatt = null;
}
}
}
});
}
else {
bluetoothGatt.close();
bluetoothGatt = null;
}
} }
Timber.i("Disconnecting%s", doCleanup ? " (with cleanup)" : "");
if (doCleanup) {
if (btMachineState != BT_MACHINE_STATE.BT_CLEANUP_STATE) {
setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE);
nextMachineStateStep();
}
handler.post(new Runnable() {
@Override
public void run() {
if (openRequest) {
handler.postDelayed(this, 10);
} else {
bluetoothGatt.close();
bluetoothGatt = null;
handler.removeCallbacksAndMessages(null);
}
}
});
}
else {
bluetoothGatt.close();
bluetoothGatt = null;
}
handler.removeCallbacksAndMessages(null);
callbackBtHandler = null;
} }
/** /**
@@ -586,49 +574,48 @@ 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)", descriptorRequestQueue.size(), characteristicRequestQueue.size());
descriptorRequestQueue.size(), characteristicRequestQueue.size()); return; // yes, do nothing
return; // yes, do nothing
}
// handle descriptor requests first
GattObjectValue<BluetoothGattDescriptor> descriptor = descriptorRequestQueue.poll();
if (descriptor != null) {
descriptor.gattObject.setValue(descriptor.value);
Timber.d("Write descriptor %s: %s (queue: %d %d)",
descriptor.gattObject.getUuid(), byteInHex(descriptor.gattObject.getValue()),
descriptorRequestQueue.size(), characteristicRequestQueue.size());
if (!bluetoothGatt.writeDescriptor(descriptor.gattObject)) {
Timber.e("Failed to initiate write of descriptor %s",
descriptor.gattObject.getUuid());
}
openRequest = true;
return;
}
// handle characteristics requests second
GattObjectValue<BluetoothGattCharacteristic> characteristic = characteristicRequestQueue.poll();
if (characteristic != null) {
characteristic.gattObject.setValue(characteristic.value);
Timber.d("Write characteristic %s: %s (queue: %d %d)",
characteristic.gattObject.getUuid(), byteInHex(characteristic.gattObject.getValue()),
descriptorRequestQueue.size(), characteristicRequestQueue.size());
if (!bluetoothGatt.writeCharacteristic(characteristic.gattObject)) {
Timber.e("Failed to initiate write of characteristic %s",
characteristic.gattObject.getUuid());
}
openRequest = true;
return;
}
// After every command was executed, continue with the next step
nextMachineStateStep();
} }
// handle descriptor requests first
GattObjectValue<BluetoothGattDescriptor> descriptor = descriptorRequestQueue.poll();
if (descriptor != null) {
descriptor.gattObject.setValue(descriptor.value);
Timber.d("Write descriptor %s: %s (queue: %d %d)",
descriptor.gattObject.getUuid(), byteInHex(descriptor.gattObject.getValue()),
descriptorRequestQueue.size(), characteristicRequestQueue.size());
if (!bluetoothGatt.writeDescriptor(descriptor.gattObject)) {
Timber.e("Failed to initiate write of descriptor %s",
descriptor.gattObject.getUuid());
}
openRequest = true;
return;
}
// handle characteristics requests second
GattObjectValue<BluetoothGattCharacteristic> characteristic = characteristicRequestQueue.poll();
if (characteristic != null) {
characteristic.gattObject.setValue(characteristic.value);
Timber.d("Write characteristic %s: %s (type: %d; queue: %d %d)",
characteristic.gattObject.getUuid(), byteInHex(characteristic.gattObject.getValue()),
characteristic.gattObject.getWriteType(),
descriptorRequestQueue.size(), characteristicRequestQueue.size());
if (!bluetoothGatt.writeCharacteristic(characteristic.gattObject)) {
Timber.e("Failed to initiate write of characteristic %s",
characteristic.gattObject.getUuid());
}
openRequest = true;
return;
}
// After every command was executed, continue with the next step
nextMachineStateStep();
} }
/** /**
@@ -640,34 +627,42 @@ 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() {
stopLeScan(); @Override
} public void run() {
stopLeScan();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
gatt.readPhy(); gatt.readPhy();
} }
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()) {
} Timber.e("Could not start service discovery");
if (!gatt.discoverServices()) { setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST);
Timber.e("Could not start service discovery"); disconnect(false);
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST); }
disconnect(false); }
} }, 1000);
} }
else if (newState == BluetoothProfile.STATE_DISCONNECTED) { else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
setBtStatus(connectionEstablished handler.post(new Runnable() {
? BT_STATUS_CODE.BT_CONNECTION_LOST @Override
: BT_STATUS_CODE.BT_NO_DEVICE_FOUND); public void run() {
disconnect(false); setBtStatus(connectionEstablished
? BT_STATUS_CODE.BT_CONNECTION_LOST
: BT_STATUS_CODE.BT_NO_DEVICE_FOUND);
disconnect(false);
}
});
} }
} }
@@ -677,34 +672,35 @@ public abstract class BluetoothCommunication {
status, gatt.getServices().size()); status, gatt.getServices().size());
if (gatt.getServices().isEmpty()) { if (gatt.getServices().isEmpty()) {
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "No services found"); handler.post(new Runnable() {
disconnect(false); @Override
public void run() {
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "No services found");
disconnect(false);
}
});
return; return;
} }
synchronized (lock) { // Sleeping a while after discovering services fixes connection problems.
cmdStepNr = 0; // See https://github.com/NordicSemiconductor/Android-DFU-Library/issues/10
initStepNr = 0; // for some technical background.
cleanupStepNr = 0; handler.postDelayed(new Runnable() {
@Override
public void run() {
cmdStepNr = 0;
initStepNr = 0;
cleanupStepNr = 0;
// Clear from possible previous setups // Clear from possible previous setups
characteristicRequestQueue = new LinkedList<>(); characteristicRequestQueue = new LinkedList<>();
descriptorRequestQueue = new LinkedList<>(); descriptorRequestQueue = new LinkedList<>();
openRequest = false; openRequest = false;
}
try { // Start the state machine
// Sleeping a while after discovering services fixes connection problems. setBtMachineState(BT_MACHINE_STATE.BT_INIT_STATE);
// See https://github.com/NordicSemiconductor/Android-DFU-Library/issues/10 }
// for some technical background. }, 1000);
Thread.sleep(1000);
}
catch (Exception e) {
// Empty
}
// Start the state machine
setBtMachineState(BT_MACHINE_STATE.BT_INIT_STATE);
} }
@Override @Override
@@ -723,10 +719,8 @@ 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() {
onBluetoothDataRead(gatt, characteristic, status); @Override
postDelayedHandleRequests(); public void run() {
} onBluetoothDataRead(gatt, characteristic, status);
}
});
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() {
onBluetoothDataChange(gatt, characteristic); @Override
} public void run() {
onBluetoothDataChange(gatt, characteristic);
}
});
} }
@Override @Override