mirror of
https://github.com/oliexdev/openScale.git
synced 2025-08-18 22:41:44 +02:00
Merge BLE rework/fixes done in #335
This commit is contained in:
@@ -196,6 +196,8 @@ public class OpenScale {
|
|||||||
selectScaleUser(-1);
|
selectScaleUser(-1);
|
||||||
throw new Exception("could not find the selected user");
|
throw new Exception("could not find the selected user");
|
||||||
}
|
}
|
||||||
|
Timber.d("Selected user is now %s (%d)",
|
||||||
|
selectedScaleUser.getUserName(), selectedScaleUser.getId());
|
||||||
return selectedScaleUser;
|
return selectedScaleUser;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@@ -78,10 +78,8 @@ public class BluetoothBeurerSanitas extends BluetoothCommunication {
|
|||||||
private static final UUID SERVICE_CHANGED =
|
private static final UUID SERVICE_CHANGED =
|
||||||
UUID.fromString("00002A05-0000-1000-8000-00805F9B34FB");
|
UUID.fromString("00002A05-0000-1000-8000-00805F9B34FB");
|
||||||
|
|
||||||
private static final UUID CLIENT_CHARACTERISTICS_CONFIGURATION_BEURER =
|
private static final UUID CLIENT_CHARACTERISTICS_CONFIGURATION =
|
||||||
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB");
|
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB");
|
||||||
private static final UUID CLIENT_CHARACTERISTICS_CONFIGURATION_SANITAS =
|
|
||||||
UUID.fromString("00002901-0000-1000-8000-00805F9B34FB");
|
|
||||||
|
|
||||||
private static final UUID CUSTOM_SERVICE_1 =
|
private static final UUID CUSTOM_SERVICE_1 =
|
||||||
UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB");
|
UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB");
|
||||||
@@ -156,10 +154,7 @@ public class BluetoothBeurerSanitas extends BluetoothCommunication {
|
|||||||
seenUsers = new TreeSet<>();
|
seenUsers = new TreeSet<>();
|
||||||
|
|
||||||
// Setup notification
|
// Setup notification
|
||||||
UUID clientCharacteristicsConfiguration = deviceType == DeviceType.SANITAS_SBF70_70
|
setNotificationOn(CUSTOM_SERVICE_1, CUSTOM_CHARACTERISTIC_WEIGHT, CLIENT_CHARACTERISTICS_CONFIGURATION);
|
||||||
? CLIENT_CHARACTERISTICS_CONFIGURATION_SANITAS
|
|
||||||
: CLIENT_CHARACTERISTICS_CONFIGURATION_BEURER;
|
|
||||||
setNotificationOn(CUSTOM_SERVICE_1, CUSTOM_CHARACTERISTIC_WEIGHT, clientCharacteristicsConfiguration);
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// Say "Hello" to the scale
|
// Say "Hello" to the scale
|
||||||
@@ -486,6 +481,12 @@ public class BluetoothBeurerSanitas extends BluetoothCommunication {
|
|||||||
(byte) (data[2] & 0xFF), (byte) (data[3] & 0xFF),
|
(byte) (data[2] & 0xFF), (byte) (data[3] & 0xFF),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (currentScaleUserId == 0) {
|
||||||
|
Timber.i("Initial weight set; disconnecting...");
|
||||||
|
setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -56,6 +56,7 @@ public abstract class BluetoothCommunication {
|
|||||||
|
|
||||||
private Handler callbackBtHandler;
|
private Handler callbackBtHandler;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
private static boolean autoConnect = false;
|
||||||
private BluetoothGatt bluetoothGatt;
|
private BluetoothGatt bluetoothGatt;
|
||||||
private boolean connectionEstablished;
|
private boolean connectionEstablished;
|
||||||
private BluetoothGattCallback gattCallback;
|
private BluetoothGattCallback gattCallback;
|
||||||
@@ -80,7 +81,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 +240,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 +252,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 +297,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 +322,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 +346,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
|
||||||
@@ -417,12 +407,12 @@ public abstract class BluetoothCommunication {
|
|||||||
public void connect(String hwAddress) {
|
public void connect(String hwAddress) {
|
||||||
logBluetoothStatus();
|
logBluetoothStatus();
|
||||||
|
|
||||||
|
disconnect(false);
|
||||||
|
btAdapter.cancelDiscovery();
|
||||||
|
|
||||||
// Some good tips to improve BLE connections:
|
// Some good tips to improve BLE connections:
|
||||||
// https://android.jlelse.eu/lessons-for-first-time-android-bluetooth-le-developers-i-learned-the-hard-way-fee07646624
|
// https://android.jlelse.eu/lessons-for-first-time-android-bluetooth-le-developers-i-learned-the-hard-way-fee07646624
|
||||||
|
|
||||||
btAdapter.cancelDiscovery();
|
|
||||||
stopLeScan();
|
|
||||||
|
|
||||||
// Don't do any cleanup if disconnected before fully connected
|
// Don't do any cleanup if disconnected before fully connected
|
||||||
btMachineState = BT_MACHINE_STATE.BT_CLEANUP_STATE;
|
btMachineState = BT_MACHINE_STATE.BT_CLEANUP_STATE;
|
||||||
|
|
||||||
@@ -436,7 +426,7 @@ public abstract class BluetoothCommunication {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Timber.d("No coarse location permission, connecting without LE scan");
|
Timber.d("No coarse location permission, connecting without LE scan");
|
||||||
connectGatt(hwAddress);
|
connectGatt(btAdapter.getRemoteDevice(hwAddress));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,49 +448,53 @@ public abstract class BluetoothCommunication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void connectGatt(BluetoothDevice device) {
|
private void connectGatt(BluetoothDevice device) {
|
||||||
Timber.i("Connecting to [%s] (driver: %s)", device.getAddress(), driverName());
|
Timber.i("Connecting to [%s] (%sdriver: %s)",
|
||||||
|
device.getAddress(), autoConnect ? "auto connect, " : "", driverName());
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
bluetoothGatt = device.connectGatt(
|
bluetoothGatt = device.connectGatt(
|
||||||
context, false, gattCallback, BluetoothDevice.TRANSPORT_LE);
|
context, autoConnect, gattCallback, BluetoothDevice.TRANSPORT_LE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bluetoothGatt = device.connectGatt(context, false, gattCallback);
|
bluetoothGatt = device.connectGatt(context, autoConnect, gattCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectGatt(String hwAddress) {
|
|
||||||
connectGatt(btAdapter.getRemoteDevice(hwAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startLeScanForDevice(final String hwAddress) {
|
private void startLeScanForDevice(final String hwAddress) {
|
||||||
leScanCallback = new BluetoothAdapter.LeScanCallback() {
|
leScanCallback = new BluetoothAdapter.LeScanCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
|
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
|
||||||
Timber.d("Found LE device %s [%s]", device.getName(), device.getAddress());
|
Timber.d("Found LE device %s [%s]", device.getName(), device.getAddress());
|
||||||
if (!device.getAddress().equals(hwAddress)) {
|
if (!device.getAddress().equals(hwAddress)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
synchronized (lock) {
|
// Stop timeout and connect to the device on the main thread
|
||||||
stopLeScan();
|
handler.removeCallbacksAndMessages(leScanCallback);
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Check that bluetoothGatt == null in case the same device is found multiple times
|
||||||
|
// and thus multiple calls to connect to it are queued. Only the first will
|
||||||
|
// trigger the connect.
|
||||||
|
if (bluetoothGatt == null) {
|
||||||
connectGatt(device);
|
connectGatt(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Timber.d("Starting LE scan for device [%s]", hwAddress);
|
// Try to connect to the device directly if the device isn't found in time
|
||||||
btAdapter.startLeScan(leScanCallback);
|
|
||||||
|
|
||||||
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) {
|
connectGatt(btAdapter.getRemoteDevice(hwAddress));
|
||||||
stopLeScan();
|
|
||||||
connectGatt(hwAddress);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, leScanCallback, SystemClock.uptimeMillis() + LE_SCAN_TIMEOUT_MS);
|
}, leScanCallback, SystemClock.uptimeMillis() + LE_SCAN_TIMEOUT_MS);
|
||||||
|
|
||||||
|
Timber.d("Starting LE scan for device [%s]", hwAddress);
|
||||||
|
btAdapter.startLeScan(leScanCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopLeScan() {
|
private void stopLeScan() {
|
||||||
@@ -516,10 +510,11 @@ 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) {
|
||||||
|
// Could be a pending connectGatt waiting
|
||||||
|
handler.removeCallbacksAndMessages(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,13 +531,10 @@ 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();
|
disconnect(false);
|
||||||
bluetoothGatt = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -552,7 +544,6 @@ public abstract class BluetoothCommunication {
|
|||||||
bluetoothGatt = null;
|
bluetoothGatt = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke next step for internal Bluetooth state machine.
|
* Invoke next step for internal Bluetooth state machine.
|
||||||
@@ -581,7 +572,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)",
|
||||||
@@ -610,8 +600,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",
|
||||||
@@ -624,46 +615,52 @@ 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.
|
||||||
*/
|
*/
|
||||||
protected class GattCallback extends BluetoothGattCallback {
|
protected class GattCallback extends BluetoothGattCallback {
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
|
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, int newState) {
|
||||||
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) {
|
|
||||||
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()) {
|
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() {
|
||||||
|
if (connectionEstablished && status != 0) {
|
||||||
|
autoConnect = !autoConnect;
|
||||||
|
}
|
||||||
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
|
||||||
@@ -672,12 +669,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;
|
||||||
@@ -686,21 +693,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) {
|
||||||
@@ -718,11 +716,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,27 +737,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
|
||||||
|
@@ -74,13 +74,28 @@ public class BluetoothDebug extends BluetoothCommunication {
|
|||||||
return names.substring(0, names.length() - 2);
|
return names.substring(0, names.length() - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String writeTypeToString(int type) {
|
||||||
|
if (type == BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) {
|
||||||
|
return "no response";
|
||||||
|
}
|
||||||
|
if (type == BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT) {
|
||||||
|
return "default";
|
||||||
|
}
|
||||||
|
if (type == BluetoothGattCharacteristic.WRITE_TYPE_SIGNED) {
|
||||||
|
return "signed";
|
||||||
|
}
|
||||||
|
return String.format("unknown type %d", type);
|
||||||
|
}
|
||||||
|
|
||||||
private void logService(BluetoothGattService service, boolean included) {
|
private void logService(BluetoothGattService service, boolean included) {
|
||||||
Timber.d("Service %s%s", service.getUuid(), included ? " (included)" : "");
|
Timber.d("Service %s%s", service.getUuid(), included ? " (included)" : "");
|
||||||
|
|
||||||
for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
|
for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
|
||||||
Timber.d("|- characteristic %s (instance %d): %s (permissions=0x%x)",
|
Timber.d("|- characteristic %s (instance %d): %s, write type: %s (permissions=0x%x)",
|
||||||
characteristic.getUuid(), characteristic.getInstanceId(),
|
characteristic.getUuid(), characteristic.getInstanceId(),
|
||||||
propertiesToString(characteristic.getProperties()), characteristic.getPermissions());
|
propertiesToString(characteristic.getProperties()),
|
||||||
|
writeTypeToString(characteristic.getWriteType()),
|
||||||
|
characteristic.getPermissions());
|
||||||
byte[] value = characteristic.getValue();
|
byte[] value = characteristic.getValue();
|
||||||
if (value != null && value.length > 0) {
|
if (value != null && value.length > 0) {
|
||||||
Timber.d("|--> value: %s (%s)", byteInHex(value),
|
Timber.d("|--> value: %s (%s)", byteInHex(value),
|
||||||
|
Reference in New Issue
Block a user