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<BluetoothGattCharacteristic>> characteristicRequestQueue;
private boolean openRequest;
private final Object lock = new Object();
public BluetoothCommunication(Context context)
{
@@ -240,10 +239,8 @@ public abstract class BluetoothCommunication {
* @param btMachineState the machine state that should be set.
*/
protected void setBtMachineState(BT_MACHINE_STATE btMachineState) {
synchronized (lock) {
this.btMachineState = btMachineState;
handleRequests();
}
this.btMachineState = btMachineState;
handleRequests();
}
/**
@@ -254,13 +251,11 @@ public abstract class BluetoothCommunication {
* @param bytes the bytes that should be write
*/
protected void writeBytes(UUID service, UUID characteristic, byte[] bytes) {
synchronized (lock) {
characteristicRequestQueue.add(
new GattObjectValue<>(
bluetoothGatt.getService(service).getCharacteristic(characteristic),
bytes));
handleRequests();
}
characteristicRequestQueue.add(
new GattObjectValue<>(
bluetoothGatt.getService(service).getCharacteristic(characteristic),
bytes));
handleRequests();
}
/**
@@ -301,13 +296,11 @@ public abstract class BluetoothCommunication {
bluetoothGatt.getService(service).getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
synchronized (lock) {
descriptorRequestQueue.add(
new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE));
handleRequests();
}
descriptorRequestQueue.add(
new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE));
handleRequests();
}
catch (Exception e) {
Timber.e(e);
@@ -328,13 +321,11 @@ public abstract class BluetoothCommunication {
bluetoothGatt.getService(service).getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
synchronized (lock) {
descriptorRequestQueue.add(
new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE));
handleRequests();
}
descriptorRequestQueue.add(
new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE));
handleRequests();
}
catch (Exception e) {
Timber.e(e);
@@ -354,13 +345,11 @@ public abstract class BluetoothCommunication {
bluetoothGatt.getService(service).getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, false);
synchronized (lock) {
descriptorRequestQueue.add(
new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE));
handleRequests();
}
descriptorRequestQueue.add(
new GattObjectValue<>(
gattCharacteristic.getDescriptor(descriptor),
BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE));
handleRequests();
}
/**
@@ -415,6 +404,8 @@ public abstract class BluetoothCommunication {
* @param hwAddress the Bluetooth address to connect to
*/
public void connect(String hwAddress) {
disconnect(false);
logBluetoothStatus();
// Some good tips to improve BLE connections:
@@ -481,6 +472,7 @@ public abstract class BluetoothCommunication {
if (!device.getAddress().equals(hwAddress)) {
return;
}
// Stop scan and connect to the device on the main thread
handler.post(new Runnable() {
@Override
public void run() {
@@ -496,14 +488,13 @@ public abstract class BluetoothCommunication {
Timber.d("Starting LE scan for device [%s]", hwAddress);
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() {
@Override
public void run() {
Timber.d("Device not found in LE scan, connecting directly");
synchronized (lock) {
stopLeScan();
connectGatt(hwAddress);
}
stopLeScan();
connectGatt(hwAddress);
}
}, leScanCallback, SystemClock.uptimeMillis() + LE_SCAN_TIMEOUT_MS);
}
@@ -521,42 +512,39 @@ public abstract class BluetoothCommunication {
* Disconnect from a Bluetooth device
*/
public void disconnect(boolean doCleanup) {
synchronized (lock) {
stopLeScan();
stopLeScan();
if (bluetoothGatt == null) {
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;
}
if (bluetoothGatt == null) {
return;
}
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() {
synchronized (lock) {
// check for pending request
if (openRequest) {
Timber.d("Request pending (queue %d %d)",
descriptorRequestQueue.size(), characteristicRequestQueue.size());
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();
// check for pending request
if (openRequest) {
Timber.d("Request pending (queue %d %d)",
descriptorRequestQueue.size(), characteristicRequestQueue.size());
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 (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);
if (newState == BluetoothProfile.STATE_CONNECTED) {
synchronized (lock) {
stopLeScan();
}
handler.post(new Runnable() {
@Override
public void run() {
stopLeScan();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
gatt.readPhy();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
gatt.readPhy();
}
connectionEstablished = true;
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED);
connectionEstablished = true;
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED);
}
});
try {
Thread.sleep(1000);
}
catch (Exception e) {
// Empty
}
if (!gatt.discoverServices()) {
Timber.e("Could not start service discovery");
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST);
disconnect(false);
}
// Wait a short while after connecting before scanning for services
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (!gatt.discoverServices()) {
Timber.e("Could not start service discovery");
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST);
disconnect(false);
}
}
}, 1000);
}
else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
setBtStatus(connectionEstablished
? BT_STATUS_CODE.BT_CONNECTION_LOST
: BT_STATUS_CODE.BT_NO_DEVICE_FOUND);
disconnect(false);
handler.post(new Runnable() {
@Override
public void run() {
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());
if (gatt.getServices().isEmpty()) {
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "No services found");
disconnect(false);
handler.post(new Runnable() {
@Override
public void run() {
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "No services found");
disconnect(false);
}
});
return;
}
synchronized (lock) {
cmdStepNr = 0;
initStepNr = 0;
cleanupStepNr = 0;
// 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;
initStepNr = 0;
cleanupStepNr = 0;
// Clear from possible previous setups
characteristicRequestQueue = new LinkedList<>();
descriptorRequestQueue = new LinkedList<>();
openRequest = false;
}
// Clear from possible previous setups
characteristicRequestQueue = new LinkedList<>();
descriptorRequestQueue = new LinkedList<>();
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
setBtMachineState(BT_MACHINE_STATE.BT_INIT_STATE);
// Start the state machine
setBtMachineState(BT_MACHINE_STATE.BT_INIT_STATE);
}
}, 1000);
}
@Override
@@ -723,10 +719,8 @@ public abstract class BluetoothCommunication {
handler.postDelayed(new Runnable() {
@Override
public void run() {
synchronized (lock) {
openRequest = false;
handleRequests();
}
openRequest = false;
handleRequests();
}
}, 60);
}
@@ -746,27 +740,33 @@ public abstract class BluetoothCommunication {
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
public void onCharacteristicRead(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic,
final int status) {
Timber.d("onCharacteristicRead %s (status=%d): %s",
characteristic.getUuid(), status, byteInHex(characteristic.getValue()));
synchronized (lock) {
onBluetoothDataRead(gatt, characteristic, status);
postDelayedHandleRequests();
}
handler.post(new Runnable() {
@Override
public void run() {
onBluetoothDataRead(gatt, characteristic, status);
}
});
postDelayedHandleRequests();
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
public void onCharacteristicChanged(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic) {
Timber.d("onCharacteristicChanged %s: %s",
characteristic.getUuid(), byteInHex(characteristic.getValue()));
synchronized (lock) {
onBluetoothDataChange(gatt, characteristic);
}
handler.post(new Runnable() {
@Override
public void run() {
onBluetoothDataChange(gatt, characteristic);
}
});
}
@Override