Added population of device info from BLE2 data source, and added auto-reconnect if the device disconnects. Note, if it disconnects for too long, the Pinetime goes to sleep and you need to press the button to re-enable it to clear the FAULT condition. This needs a PineTime firmware change to fix it.

This commit is contained in:
Graham Jones
2024-04-11 16:13:47 +01:00
parent 24cf171952
commit 532c2f0741
2 changed files with 92 additions and 21 deletions

View File

@@ -83,6 +83,8 @@ public class SdData implements Parcelable {
/* Watch App Settings */ /* Watch App Settings */
public String dataSourceName = ""; public String dataSourceName = "";
public String watchManuf = "";
public String watchSerNo = "";
public String watchPartNo = ""; public String watchPartNo = "";
public String watchFwVersion = ""; public String watchFwVersion = "";
public String watchSdVersion = ""; public String watchSdVersion = "";
@@ -314,7 +316,9 @@ public class SdData implements Parcelable {
jsonObj.put("dataSourceName", dataSourceName); jsonObj.put("dataSourceName", dataSourceName);
Log.v(TAG, "phoneAppVersion=" + phoneAppVersion); Log.v(TAG, "phoneAppVersion=" + phoneAppVersion);
jsonObj.put("phoneAppVersion", phoneAppVersion); jsonObj.put("phoneAppVersion", phoneAppVersion);
jsonObj.put("watchManuf", watchManuf);
jsonObj.put("watchPartNo", watchPartNo); jsonObj.put("watchPartNo", watchPartNo);
jsonObj.put("watchSerNo", watchSerNo);
jsonObj.put("watchSdName", watchSdName); jsonObj.put("watchSdName", watchSdName);
jsonObj.put("watchFwVersion", watchFwVersion); jsonObj.put("watchFwVersion", watchFwVersion);
jsonObj.put("watchSdVersion", watchSdVersion); jsonObj.put("watchSdVersion", watchSdVersion);

View File

@@ -88,6 +88,12 @@ public class SdDataSourceBLE2 extends SdDataSource {
public static String SERV_DEV_INFO = "0000180a-0000-1000-8000-00805f9b34fb"; public static String SERV_DEV_INFO = "0000180a-0000-1000-8000-00805f9b34fb";
public static String CHAR_DEV_MANUF = "00002a29-0000-1000-8000-00805f9b34fb";
public static String CHAR_DEV_MODEL_NO = "00002a24-0000-1000-8000-00805f9b34fb";
public static String CHAR_DEV_SER_NO = "00002a25-0000-1000-8000-00805f9b34fb";
public static String CHAR_DEV_FW_VER = "00002a26-0000-1000-8000-00805f9b34fb";
public static String CHAR_DEV_HW_VER = "00002a27-0000-1000-8000-00805f9b34fb";
public static String CHAR_DEV_FW_NAME = "00002a28-0000-1000-8000-00805f9b34fb";
public static String SERV_HEART_RATE = "0000180d-0000-1000-8000-00805f9b34fb"; public static String SERV_HEART_RATE = "0000180d-0000-1000-8000-00805f9b34fb";
public static String CHAR_HEART_RATE_MEASUREMENT = "00002a37-0000-1000-8000-00805f9b34fb"; public static String CHAR_HEART_RATE_MEASUREMENT = "00002a37-0000-1000-8000-00805f9b34fb";
@@ -174,7 +180,7 @@ public class SdDataSourceBLE2 extends SdDataSource {
public void onDiscoveredPeripheral(BluetoothPeripheral peripheral, ScanResult scanResult) { public void onDiscoveredPeripheral(BluetoothPeripheral peripheral, ScanResult scanResult) {
Log.i(TAG,"BluetoothCentralManagerCallback.onDiscoveredPeripheral()"); Log.i(TAG,"BluetoothCentralManagerCallback.onDiscoveredPeripheral()");
mBluetoothCentralManager.stopScan(); mBluetoothCentralManager.stopScan();
mBluetoothCentralManager.connectPeripheral(peripheral, peripheralCallback); mBluetoothCentralManager.autoConnectPeripheral(peripheral, peripheralCallback);
} }
@Override @Override
public void onConnectedPeripheral(BluetoothPeripheral peripheral) { public void onConnectedPeripheral(BluetoothPeripheral peripheral) {
@@ -183,12 +189,14 @@ public class SdDataSourceBLE2 extends SdDataSource {
} }
@Override @Override
public void onConnectionFailed(BluetoothPeripheral peripheral, HciStatus status) { public void onConnectionFailed(BluetoothPeripheral peripheral, HciStatus status) {
Log.i(TAG,"BluetoothCentralManagerCallback.onConnectionFailed()"); Log.i(TAG,"BluetoothCentralManagerCallback.onConnectionFailed() - attempting to reconnect");
mBluetoothCentralManager.autoConnectPeripheral(peripheral, peripheralCallback);
super.onConnectionFailed(peripheral, status); super.onConnectionFailed(peripheral, status);
} }
@Override @Override
public void onDisconnectedPeripheral(BluetoothPeripheral peripheral, HciStatus status) { public void onDisconnectedPeripheral(BluetoothPeripheral peripheral, HciStatus status) {
Log.i(TAG,"BluetoothCentralManagerCallback.onDisonnectedPeripheral"); Log.i(TAG,"BluetoothCentralManagerCallback.onDisonnectedPeripheral - attempting to re-connect...");
mBluetoothCentralManager.autoConnectPeripheral(peripheral, peripheralCallback);
super.onDisconnectedPeripheral(peripheral, status); super.onDisconnectedPeripheral(peripheral, status);
} }
@@ -201,12 +209,18 @@ public class SdDataSourceBLE2 extends SdDataSource {
@Override // BluetoothPeripheralCallback @Override // BluetoothPeripheralCallback
public void onServicesDiscovered(@NotNull BluetoothPeripheral peripheral) { public void onServicesDiscovered(@NotNull BluetoothPeripheral peripheral) {
Log.i(TAG,"onServicesDiscovered()");
mBlePeripheral = peripheral; mBlePeripheral = peripheral;
// Request a higher MTU, iOS always asks for 185 // Request a higher MTU, iOS always asks for 185 - This is likely to have no effect, as Pinetime uses 23 bytes.
Log.i(TAG,"onServicesDiscovered() - requesting higher MTU");
peripheral.requestMtu(185); peripheral.requestMtu(185);
// Request a new connection priority // Request a new connection priority
Log.i(TAG,"onServicesDiscovered() - requesting high priority connection");
peripheral.requestConnectionPriority(ConnectionPriority.HIGH); peripheral.requestConnectionPriority(ConnectionPriority.HIGH);
peripheral.setPreferredPhy(PhyType.LE_2M, PhyType.LE_2M, PhyOptions.S2); Log.i(TAG,"onServicesDiscovered() - requesting Long Range Bluetooth 5 connection");
//peripheral.setPreferredPhy(PhyType.LE_2M, PhyType.LE_2M, PhyOptions.S2);
// Request long range Bluetooth 5 connection if available.
peripheral.setPreferredPhy(PhyType.LE_CODED, PhyType.LE_CODED, PhyOptions.S8);
peripheral.readPhy(); peripheral.readPhy();
boolean foundOsdService = false; boolean foundOsdService = false;
@@ -219,13 +233,20 @@ public class SdDataSourceBLE2 extends SdDataSource {
} else if (servUuidStr.equals(SERV_INFINITIME_MOTION)) { } else if (servUuidStr.equals(SERV_INFINITIME_MOTION)) {
Log.v(TAG, "InfiniTime Motion Service Discovered"); Log.v(TAG, "InfiniTime Motion Service Discovered");
foundOsdService = true; foundOsdService = true;
} else if (servUuidStr.equals(SERV_HEART_RATE)) {
Log.v(TAG, "Heart Rate Measurement Service Service Discovered");
} else if (servUuidStr.equals(SERV_BATT)) { } else if (servUuidStr.equals(SERV_BATT)) {
Log.v(TAG, "Battery Data Service Service Discovered"); Log.v(TAG, "Battery Data Service Service Discovered");
} else if (servUuidStr.equals(SERV_DEV_INFO)) {
Log.v(TAG, "Device Information Service Service Discovered");
} }
// Loop through the available characteristics... // Loop through the available characteristics...
for (BluetoothGattCharacteristic gattCharacteristic : service.getCharacteristics()) { for (BluetoothGattCharacteristic gattCharacteristic : service.getCharacteristics()) {
String charUuidStr = gattCharacteristic.getUuid().toString(); String charUuidStr = gattCharacteristic.getUuid().toString();
Log.d(TAG, " found characteristic: " + charUuidStr); Log.d(TAG, " found characteristic: " + charUuidStr);
// The generic heart rate measurement characteristic
if (charUuidStr.equals(CHAR_HEART_RATE_MEASUREMENT)) { if (charUuidStr.equals(CHAR_HEART_RATE_MEASUREMENT)) {
Log.v(TAG, "Subscribing to Heart Rate Measurement Change Notifications"); Log.v(TAG, "Subscribing to Heart Rate Measurement Change Notifications");
mHrChar = gattCharacteristic; mHrChar = gattCharacteristic;
@@ -255,19 +276,38 @@ public class SdDataSourceBLE2 extends SdDataSource {
} else if (charUuidStr.equals(CHAR_INFINITIME_ACC_DATA)) { } else if (charUuidStr.equals(CHAR_INFINITIME_ACC_DATA)) {
Log.i(TAG, "Subscribing to Infinitime Acceleration Data Change Notifications"); Log.i(TAG, "Subscribing to Infinitime Acceleration Data Change Notifications");
mOsdChar = gattCharacteristic; mOsdChar = gattCharacteristic;
mAccFmt = ACC_FMT_3D; // Infinitime presents x, y, z data mAccFmt = ACC_FMT_3D; // InfiniTime presents x, y, z data
peripheral.setNotify(service.getUuid(), gattCharacteristic.getUuid(), true); peripheral.setNotify(service.getUuid(), gattCharacteristic.getUuid(), true);
} else if (charUuidStr.equals(CHAR_INFINITIME_OSD_STATUS)) { } else if (charUuidStr.equals(CHAR_INFINITIME_OSD_STATUS)) {
Log.i(TAG, "Found Infinitime OSD Status Characteristic"); Log.i(TAG, "Found InfiniTime OSD Status Characteristic");
mStatusChar = gattCharacteristic; mStatusChar = gattCharacteristic;
// Now the generic battery data characteristic
} else if (charUuidStr.equals(CHAR_BATT_DATA)) { } else if (charUuidStr.equals(CHAR_BATT_DATA)) {
mBattChar = gattCharacteristic; mBattChar = gattCharacteristic;
Log.i(TAG, "Subscribing to Generic Battery Data Change Notifications"); Log.i(TAG, "Subscribing to Generic Battery Data Change Notifications");
peripheral.setNotify(service.getUuid(), gattCharacteristic.getUuid(), true); peripheral.setNotify(service.getUuid(), gattCharacteristic.getUuid(), true);
Log.i(TAG, "Reading battery level"); Log.i(TAG, "Reading battery level");
peripheral.readCharacteristic(service.getUuid(), gattCharacteristic.getUuid()); peripheral.readCharacteristic(service.getUuid(), gattCharacteristic.getUuid());
// Now device info characteristics
} else if (charUuidStr.equals(CHAR_DEV_MANUF)) {
Log.i(TAG, "Reading device manufacturer");
peripheral.readCharacteristic(service.getUuid(), gattCharacteristic.getUuid());
} else if (charUuidStr.equals(CHAR_DEV_MODEL_NO)) {
Log.i(TAG, "Reading device model number");
peripheral.readCharacteristic(service.getUuid(), gattCharacteristic.getUuid());
} else if (charUuidStr.equals(CHAR_DEV_SER_NO)) {
Log.i(TAG, "Reading device serial number");
peripheral.readCharacteristic(service.getUuid(), gattCharacteristic.getUuid());
} else if (charUuidStr.equals(CHAR_DEV_FW_VER)) {
Log.i(TAG, "Reading device firmware version");
peripheral.readCharacteristic(service.getUuid(), gattCharacteristic.getUuid());
} else if (charUuidStr.equals(CHAR_DEV_HW_VER)) {
Log.i(TAG, "Reading device hardware version");
peripheral.readCharacteristic(service.getUuid(), gattCharacteristic.getUuid());
} else if (charUuidStr.equals(CHAR_DEV_FW_NAME)) {
Log.i(TAG, "Reading device firmware name");
peripheral.readCharacteristic(service.getUuid(), gattCharacteristic.getUuid());
} }
} }
} }
if (foundOsdService) { if (foundOsdService) {
@@ -293,9 +333,9 @@ public class SdDataSourceBLE2 extends SdDataSource {
@Override @Override
public void onCharacteristicWrite(@NotNull BluetoothPeripheral peripheral, @NotNull byte[] value, @NotNull BluetoothGattCharacteristic characteristic, @NotNull GattStatus status) { public void onCharacteristicWrite(@NotNull BluetoothPeripheral peripheral, @NotNull byte[] value, @NotNull BluetoothGattCharacteristic characteristic, @NotNull GattStatus status) {
if (status == GattStatus.SUCCESS) { if (status == GattStatus.SUCCESS) {
Log.i(TAG, String.format("SUCCESS: Writing <%s> to <%s>", asHexString(value), characteristic.getUuid())); Log.d(TAG, String.format("SUCCESS: Writing <%s> to <%s>", asHexString(value), characteristic.getUuid()));
} else { } else {
Log.i(TAG, String.format("ERROR: Failed writing <%s> to <%s> (%s)", asHexString(value), characteristic.getUuid(), status)); Log.w(TAG, String.format("ERROR: Failed writing <%s> to <%s> (%s)", asHexString(value), characteristic.getUuid(), status));
} }
} }
@@ -391,22 +431,49 @@ public class SdDataSourceBLE2 extends SdDataSource {
mSdData.batteryPc = batteryPc; mSdData.batteryPc = batteryPc;
Log.v(TAG, "onDataReceived(): CHAR_BATT_DATA: " + String.format("%d", batteryPc)); Log.v(TAG, "onDataReceived(): CHAR_BATT_DATA: " + String.format("%d", batteryPc));
mSdData.haveSettings = true; mSdData.haveSettings = true;
} else if (charUuidStr.equals(CHAR_OSD_WATCH_ID)) { } else if (charUuidStr.equals(CHAR_OSD_WATCH_ID) || charUuidStr.equals(CHAR_DEV_FW_NAME)) {
byte[] rawDataBytes = characteristic.getValue(); byte[] rawDataBytes = characteristic.getValue();
String watchId = new String(rawDataBytes, StandardCharsets.UTF_8); String watchId = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.v(TAG, "Received Watch ID: " + watchId); Log.i(TAG, "Received Watch ID: " + watchId);
mSdData.watchSdName = watchId; mSdData.watchSdName = watchId;
} else if (charUuidStr.equals(CHAR_OSD_WATCH_FW)) {
byte[] rawDataBytes = characteristic.getValue();
String watchFwVer = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.v(TAG, "Received Watch Firmware Version: " + watchFwVer);
mSdData.watchSdVersion = watchFwVer;
} else if (charUuidStr.equals(CHAR_OSD_ACC_FMT)) { } else if (charUuidStr.equals(CHAR_OSD_ACC_FMT)) {
mAccFmt = characteristic.getValue()[0]; mAccFmt = characteristic.getValue()[0];
Log.v(TAG, "Received Acceleration format code: " + mAccFmt); Log.i(TAG, "Received Acceleration format code: " + mAccFmt);
} else if (charUuidStr.equals(CHAR_DEV_MANUF)) {
byte[] rawDataBytes = characteristic.getValue();
String watchManuf = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.i(TAG, "Received Manufacturer: " + watchManuf);
mSdData.watchManuf = watchManuf;
} else if (charUuidStr.equals(CHAR_DEV_MODEL_NO)) {
byte[] rawDataBytes = characteristic.getValue();
String watchModelNo = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.i(TAG, "Received Watch Model No.: " + watchModelNo);
mSdData.watchPartNo = watchModelNo;
} else if (charUuidStr.equals(CHAR_DEV_SER_NO)) {
byte[] rawDataBytes = characteristic.getValue();
String watchSerNo = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.i(TAG, "Received Watch Serial No.: " + watchSerNo);
mSdData.watchSerNo = watchSerNo;
} else if (charUuidStr.equals(CHAR_DEV_HW_VER)) {
byte[] rawDataBytes = characteristic.getValue();
String watchHwVer = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.i(TAG, "Received Hardware Version: " + watchHwVer);
mSdData.watchFwVersion = watchHwVer;
} else if (charUuidStr.equals(CHAR_DEV_FW_NAME)) {
byte[] rawDataBytes = characteristic.getValue();
String watchFwName = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.i(TAG, "Received Firmware Name: " + watchFwName);
mSdData.watchSdName = watchFwName;
} else if (charUuidStr.equals(CHAR_OSD_WATCH_FW) || charUuidStr.equals(CHAR_DEV_FW_VER)) {
byte[] rawDataBytes = characteristic.getValue();
String watchFwVer = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.i(TAG, "Received Watch Firmware Version: " + watchFwVer);
mSdData.watchSdVersion = watchFwVer;
} else { } else {
Log.v(TAG, "Unrecognised Characteristic Updated " + byte[] rawDataBytes = characteristic.getValue();
charUuidStr); String strVal = new String(rawDataBytes, StandardCharsets.UTF_8);
Log.d(TAG, "Unrecognised Characteristic Updated " +
charUuidStr+" : "+strVal);
} }
} }