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:
@@ -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
|
||||||
|
Reference in New Issue
Block a user