From 8e6f39dbe777f11cb7c8ac4143a78e529b0d76fa Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sun, 12 Dec 2021 13:12:20 +0100 Subject: [PATCH] RileyLinkBLE -> kt --- .../pump/common/hw/rileylink/ble/RFSpy.java | 6 +- .../common/hw/rileylink/ble/RFSpyReader.java | 2 +- .../common/hw/rileylink/ble/RileyLinkBLE.java | 639 ------------------ .../common/hw/rileylink/ble/RileyLinkBLE.kt | 447 ++++++++++++ .../hw/rileylink/ble/device/OrangeLinkImpl.kt | 8 +- 5 files changed, 454 insertions(+), 648 deletions(-) delete mode 100644 rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.java create mode 100644 rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.kt diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java index 2304aa9bf5..4d6e7bb477 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java @@ -116,7 +116,7 @@ public class RFSpy { } public Integer retrieveBatteryLevel() { - BLECommOperationResult result = rileyLinkBle.readCharacteristic_blocking(batteryServiceUUID, batteryLevelUUID); + BLECommOperationResult result = rileyLinkBle.readCharacteristicBlocking(batteryServiceUUID, batteryLevelUUID); if (result.resultCode == BLECommOperationResult.RESULT_SUCCESS) { if (ArrayUtils.isNotEmpty(result.value)) { int value = result.value[0]; @@ -134,7 +134,7 @@ public class RFSpy { // This gets the version from the BLE113, not from the CC1110. // I.e., this gets the version from the BLE interface, not from the radio. public String getVersion() { - BLECommOperationResult result = rileyLinkBle.readCharacteristic_blocking(radioServiceUUID, radioVersionUUID); + BLECommOperationResult result = rileyLinkBle.readCharacteristicBlocking(radioServiceUUID, radioVersionUUID); if (result.resultCode == BLECommOperationResult.RESULT_SUCCESS) { String version = StringUtil.fromBytes(result.value); aapsLogger.debug(LTag.PUMPBTCOMM, "BLE Version: " + version); @@ -208,7 +208,7 @@ public class RFSpy { aapsLogger.debug(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "writeToData (raw=%s)", ByteUtil.shortHexString(prepended))); - BLECommOperationResult writeCheck = rileyLinkBle.writeCharacteristic_blocking(radioServiceUUID, radioDataUUID, + BLECommOperationResult writeCheck = rileyLinkBle.writeCharacteristicBlocking(radioServiceUUID, radioDataUUID, prepended); if (writeCheck.resultCode != BLECommOperationResult.RESULT_SUCCESS) { aapsLogger.error(LTag.PUMPBTCOMM, "BLE Write operation failed, code=" + writeCheck.resultCode); diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpyReader.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpyReader.java index 9b0f1ac1eb..c5fa369a07 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpyReader.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpyReader.java @@ -107,7 +107,7 @@ public class RFSpyReader { + SystemClock.uptimeMillis()); SystemClock.sleep(100); SystemClock.sleep(1); - result = rileyLinkBle.readCharacteristic_blocking(serviceUUID, radioDataUUID); + result = rileyLinkBle.readCharacteristicBlocking(serviceUUID, radioDataUUID); SystemClock.sleep(100); if (result.resultCode == BLECommOperationResult.RESULT_SUCCESS) { diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.java deleted file mode 100644 index 704b797c90..0000000000 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.java +++ /dev/null @@ -1,639 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCallback; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattDescriptor; -import android.bluetooth.BluetoothGattService; -import android.bluetooth.BluetoothProfile; -import android.content.Context; -import android.os.SystemClock; - -import org.apache.commons.lang3.StringUtils; - -import java.util.List; -import java.util.Locale; -import java.util.UUID; -import java.util.concurrent.Semaphore; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.shared.logging.AAPSLogger; -import info.nightscout.shared.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.GattAttributes; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.device.OrangeLinkImpl; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.BLECommOperation; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.BLECommOperationResult; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.CharacteristicReadOperation; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.CharacteristicWriteOperation; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.DescriptorWriteOperation; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkError; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.ThreadUtil; -import info.nightscout.shared.sharedPreferences.SP; - -/** - * Created by geoff on 5/26/16. - * Added: State handling, configuration of RF for different configuration ranges, connection handling - */ -@Singleton -public class RileyLinkBLE { - - @Inject AAPSLogger aapsLogger; - @Inject RileyLinkServiceData rileyLinkServiceData; - @Inject RileyLinkUtil rileyLinkUtil; - @Inject SP sp; - @Inject OrangeLinkImpl orangeLink; - - private final Context context; - private final boolean gattDebugEnabled = true; - private boolean manualDisconnect = false; - private final BluetoothAdapter bluetoothAdapter; - private final BluetoothGattCallback bluetoothGattCallback; - private BluetoothDevice rileyLinkDevice; - private BluetoothGatt bluetoothConnectionGatt = null; - private BLECommOperation mCurrentOperation; - private final Semaphore gattOperationSema = new Semaphore(1, true); - private Runnable radioResponseCountNotified; - private boolean mIsConnected = false; - - @Inject - public RileyLinkBLE(final Context context) { - this.context = context; - this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - - //orangeLink.rileyLinkBLE = this; - - bluetoothGattCallback = new BluetoothGattCallback() { - - @Override - public void onCharacteristicChanged(final BluetoothGatt gatt, - final BluetoothGattCharacteristic characteristic) { - super.onCharacteristicChanged(gatt, characteristic); - if (gattDebugEnabled) { - aapsLogger.debug(LTag.PUMPBTCOMM, ThreadUtil.sig() + "onCharacteristicChanged " - + GattAttributes.lookup(characteristic.getUuid()) + " " - + ByteUtil.getHex(characteristic.getValue())); - if (characteristic.getUuid().equals(UUID.fromString(GattAttributes.CHARA_RADIO_RESPONSE_COUNT))) { - aapsLogger.debug(LTag.PUMPBTCOMM, "Response Count is " + ByteUtil.shortHexString(characteristic.getValue())); - } - } - if (characteristic.getUuid().equals(UUID.fromString(GattAttributes.CHARA_RADIO_RESPONSE_COUNT))) { - if (radioResponseCountNotified != null) { - radioResponseCountNotified.run(); - } - } - orangeLink.onCharacteristicChanged(characteristic); - } - - - @Override - public void onCharacteristicRead(final BluetoothGatt gatt, - final BluetoothGattCharacteristic characteristic, int status) { - super.onCharacteristicRead(gatt, characteristic, status); - - final String statusMessage = getGattStatusMessage(status); - if (gattDebugEnabled) { - aapsLogger.debug(LTag.PUMPBTCOMM, ThreadUtil.sig() + "onCharacteristicRead (" - + GattAttributes.lookup(characteristic.getUuid()) + ") " + statusMessage + ":" - + ByteUtil.getHex(characteristic.getValue())); - } - mCurrentOperation.gattOperationCompletionCallback(characteristic.getUuid(), characteristic.getValue()); - } - - - @Override - public void onCharacteristicWrite(final BluetoothGatt gatt, - final BluetoothGattCharacteristic characteristic, int status) { - super.onCharacteristicWrite(gatt, characteristic, status); - - final String uuidString = GattAttributes.lookup(characteristic.getUuid()); - if (gattDebugEnabled) { - aapsLogger.debug(LTag.PUMPBTCOMM, ThreadUtil.sig() + "onCharacteristicWrite " + getGattStatusMessage(status) + " " - + uuidString + " " + ByteUtil.shortHexString(characteristic.getValue())); - } - mCurrentOperation.gattOperationCompletionCallback(characteristic.getUuid(), characteristic.getValue()); - } - - - @Override - public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) { - super.onConnectionStateChange(gatt, status, newState); - - // https://github.com/NordicSemiconductor/puck-central-android/blob/master/PuckCentral/app/src/main/java/no/nordicsemi/puckcentral/bluetooth/gatt/GattManager.java#L117 - if (status == 133) { - aapsLogger.error(LTag.PUMPBTCOMM, "Got the status 133 bug, closing gatt"); - disconnect(); - SystemClock.sleep(500); - return; - } - - if (gattDebugEnabled) { - final String stateMessage; - if (newState == BluetoothProfile.STATE_CONNECTED) { - stateMessage = "CONNECTED"; - } else if (newState == BluetoothProfile.STATE_CONNECTING) { - stateMessage = "CONNECTING"; - } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { - stateMessage = "DISCONNECTED"; - } else if (newState == BluetoothProfile.STATE_DISCONNECTING) { - stateMessage = "DISCONNECTING"; - } else { - stateMessage = "UNKNOWN newState (" + newState + ")"; - } - - aapsLogger.warn(LTag.PUMPBTCOMM, "onConnectionStateChange " + getGattStatusMessage(status) + " " + stateMessage); - } - - if (newState == BluetoothProfile.STATE_CONNECTED) { - if (status == BluetoothGatt.GATT_SUCCESS) { - rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.BluetoothConnected, context); - } else { - aapsLogger.debug(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "BT State connected, GATT status %d (%s)", status, getGattStatusMessage(status))); - } - - } else if ((newState == BluetoothProfile.STATE_CONNECTING) || // - (newState == BluetoothProfile.STATE_DISCONNECTING)) { - aapsLogger.debug(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "We are in %s state.", status == BluetoothProfile.STATE_CONNECTING ? "Connecting" : - "Disconnecting")); - } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { - rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkDisconnected, context); - if (manualDisconnect) - close(); - aapsLogger.warn(LTag.PUMPBTCOMM, "RileyLink Disconnected."); - } else { - aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Some other state: (status=%d, newState=%d)", status, newState)); - } - } - - - @Override - public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { - super.onDescriptorWrite(gatt, descriptor, status); - if (gattDebugEnabled) { - aapsLogger.warn(LTag.PUMPBTCOMM, "onDescriptorWrite " + GattAttributes.lookup(descriptor.getUuid()) + " " - + getGattStatusMessage(status) + " written: " + ByteUtil.getHex(descriptor.getValue())); - } - mCurrentOperation.gattOperationCompletionCallback(descriptor.getUuid(), descriptor.getValue()); - } - - - @Override - public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { - super.onDescriptorRead(gatt, descriptor, status); - mCurrentOperation.gattOperationCompletionCallback(descriptor.getUuid(), descriptor.getValue()); - if (gattDebugEnabled) { - aapsLogger.warn(LTag.PUMPBTCOMM, "onDescriptorRead " + getGattStatusMessage(status) + " status " + descriptor); - } - } - - - @Override - public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { - super.onMtuChanged(gatt, mtu, status); - if (gattDebugEnabled) { - aapsLogger.warn(LTag.PUMPBTCOMM, "onMtuChanged " + mtu + " status " + status); - } - } - - - @Override - public void onReadRemoteRssi(final BluetoothGatt gatt, int rssi, int status) { - super.onReadRemoteRssi(gatt, rssi, status); - if (gattDebugEnabled) { - aapsLogger.warn(LTag.PUMPBTCOMM, "onReadRemoteRssi " + getGattStatusMessage(status) + ": " + rssi); - } - } - - - @Override - public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { - super.onReliableWriteCompleted(gatt, status); - if (gattDebugEnabled) { - aapsLogger.warn(LTag.PUMPBTCOMM, "onReliableWriteCompleted status " + status); - } - } - - - @Override - public void onServicesDiscovered(final BluetoothGatt gatt, int status) { - super.onServicesDiscovered(gatt, status); - - if (status == BluetoothGatt.GATT_SUCCESS) { - final List services = gatt.getServices(); - - boolean rileyLinkFound = false; - orangeLink.resetOrangeLinkData(); - - StringBuilder stringBuilder = new StringBuilder("RileyLink Device Debug\n"); - - for (BluetoothGattService service : services) { - final UUID uuidService = service.getUuid(); - - if (isAnyRileyLinkServiceFound(service)) { - rileyLinkFound = true; - } - - if (gattDebugEnabled) { - debugService(service, 0, stringBuilder); - } - - orangeLink.checkIsOrange(uuidService); - } - - if (gattDebugEnabled) { - aapsLogger.warn(LTag.PUMPBTCOMM, stringBuilder.toString()); - aapsLogger.warn(LTag.PUMPBTCOMM, "onServicesDiscovered " + getGattStatusMessage(status)); - } - - aapsLogger.info(LTag.PUMPBTCOMM, "Gatt device is RileyLink device: " + rileyLinkFound); - - if (rileyLinkFound) { - mIsConnected = true; - rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkReady, context); - } else { - mIsConnected = false; - rileyLinkServiceData.setServiceState(RileyLinkServiceState.RileyLinkError, - RileyLinkError.DeviceIsNotRileyLink); - } - - } else { - aapsLogger.debug(LTag.PUMPBTCOMM, "onServicesDiscovered " + getGattStatusMessage(status)); - rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkGattFailed, context); - } - } - }; - } - - @Inject - public void onInit() { - //aapsLogger.debug(LTag.PUMPBTCOMM, "BT Adapter: " + this.bluetoothAdapter); - this.orangeLink.rileyLinkBLE = this; - } - - - private boolean isAnyRileyLinkServiceFound(BluetoothGattService service) { - - boolean found = GattAttributes.isRileyLink(service.getUuid()); - - if (found) { - return true; - } else { - List includedServices = service.getIncludedServices(); - - for (BluetoothGattService serviceI : includedServices) { - if (isAnyRileyLinkServiceFound(serviceI)) { - return true; - } - orangeLink.checkIsOrange(serviceI.getUuid()); - } - } - - return false; - } - - - public BluetoothDevice getRileyLinkDevice() { - return this.rileyLinkDevice; - } - - - public void debugService(BluetoothGattService service, int indentCount, StringBuilder stringBuilder) { - - String indentString = StringUtils.repeat(' ', indentCount); - - final UUID uuidService = service.getUuid(); - - if (gattDebugEnabled) { - final String uuidServiceString = uuidService.toString(); - - //StringBuilder stringBuilder = new StringBuilder(); - - stringBuilder.append(indentString); - stringBuilder.append(GattAttributes.lookup(uuidServiceString, "Unknown service")); - stringBuilder.append(" (" + uuidServiceString + ")"); - - for (BluetoothGattCharacteristic character : service.getCharacteristics()) { - final String uuidCharacteristicString = character.getUuid().toString(); - - stringBuilder.append("\n "); - stringBuilder.append(indentString); - stringBuilder.append(" - " + GattAttributes.lookup(uuidCharacteristicString, "Unknown Characteristic")); - stringBuilder.append(" (" + uuidCharacteristicString + ")"); - } - - stringBuilder.append("\n\n"); - - //aapsLogger.warn(LTag.PUMPBTCOMM, stringBuilder.toString()); - - List includedServices = service.getIncludedServices(); - - for (BluetoothGattService serviceI : includedServices) { - debugService(serviceI, indentCount + 4, stringBuilder); - } - } - } - - - void registerRadioResponseCountNotification(Runnable notifier) { - radioResponseCountNotified = notifier; - } - - - public boolean isConnected() { - return mIsConnected; - } - - - public boolean discoverServices() { - - if (bluetoothConnectionGatt == null) { - // shouldn't happen, but if it does we exit - return false; - } - - if (bluetoothConnectionGatt.discoverServices()) { - aapsLogger.warn(LTag.PUMPBTCOMM, "Starting to discover GATT Services."); - return true; - } else { - aapsLogger.error(LTag.PUMPBTCOMM, "Cannot discover GATT Services."); - return false; - } - } - - - public boolean enableNotifications() { - BLECommOperationResult result = setNotification_blocking(UUID.fromString(GattAttributes.SERVICE_RADIO), // - UUID.fromString(GattAttributes.CHARA_RADIO_RESPONSE_COUNT)); - if (result.resultCode != BLECommOperationResult.RESULT_SUCCESS) { - aapsLogger.error(LTag.PUMPBTCOMM, "Error setting response count notification"); - return false; - } - - if (rileyLinkServiceData.isOrange) { - return orangeLink.enableNotifications(); - } - return true; - } - - - public void findRileyLink(String rileyLinkAddress) { - aapsLogger.debug(LTag.PUMPBTCOMM, "RileyLink address: " + rileyLinkAddress); - // Must verify that this is a valid MAC, or crash. - //macAddress = RileyLinkAddress; - boolean useScanning = sp.getBoolean(RileyLinkConst.Prefs.OrangeUseScanning, false); - if (useScanning) { - aapsLogger.debug(LTag.PUMPBTCOMM, "Start scan for OrangeLink device."); - orangeLink.startScan(); - } else { - rileyLinkDevice = bluetoothAdapter.getRemoteDevice(rileyLinkAddress); - // if this succeeds, we get a connection state change callback? - if (rileyLinkDevice != null) { - connectGattInternal(); - } else { - aapsLogger.error(LTag.PUMPBTCOMM, "RileyLink device not found with address: " + rileyLinkAddress); - } - } - } - - public void connectGatt() { - boolean useScanning = sp.getBoolean(RileyLinkConst.Prefs.OrangeUseScanning, false); - if (useScanning) { - aapsLogger.debug(LTag.PUMPBTCOMM, "Start scan for OrangeLink device."); - orangeLink.startScan(); - } else { - connectGattInternal(); - } - } - - - // This function must be run on UI thread. - public void connectGattInternal() { - if (this.rileyLinkDevice == null) { - aapsLogger.error(LTag.PUMPBTCOMM, "RileyLink device is null, can't do connectGatt."); - return; - } - - bluetoothConnectionGatt = rileyLinkDevice.connectGatt(context, true, bluetoothGattCallback); - // , BluetoothDevice.TRANSPORT_LE - if (bluetoothConnectionGatt == null) { - aapsLogger.error(LTag.PUMPBTCOMM, "Failed to connect to Bluetooth Low Energy device at " + bluetoothAdapter.getAddress()); - } else { - if (gattDebugEnabled) { - aapsLogger.debug(LTag.PUMPBTCOMM, "Gatt Connected."); - } - - String deviceName = bluetoothConnectionGatt.getDevice().getName(); - if (StringUtils.isNotEmpty(deviceName)) { - // Update stored name upon connecting (also for backwards compatibility for device where a name was not yet stored) - sp.putString(RileyLinkConst.Prefs.RileyLinkName, deviceName); - } else { - sp.remove(RileyLinkConst.Prefs.RileyLinkName); - } - - rileyLinkServiceData.rileyLinkName = deviceName; - rileyLinkServiceData.rileyLinkAddress = bluetoothConnectionGatt.getDevice().getAddress(); - } - } - - - public void disconnect() { - mIsConnected = false; - aapsLogger.warn(LTag.PUMPBTCOMM, "Closing GATT connection"); - // Close old conenction - if (bluetoothConnectionGatt != null) { - // Not sure if to disconnect or to close first.. - bluetoothConnectionGatt.disconnect(); - manualDisconnect = true; - } - } - - - public void close() { - if (bluetoothConnectionGatt != null) { - bluetoothConnectionGatt.close(); - bluetoothConnectionGatt = null; - } - } - - - public BLECommOperationResult setNotification_blocking(UUID serviceUUID, UUID charaUUID) { - BLECommOperationResult rval = new BLECommOperationResult(); - if (bluetoothConnectionGatt != null) { - - try { - gattOperationSema.acquire(); - SystemClock.sleep(1); // attempting to yield thread, to make sequence of events easier to follow - } catch (InterruptedException e) { - aapsLogger.error(LTag.PUMPBTCOMM, "setNotification_blocking: interrupted waiting for gattOperationSema"); - return rval; - } - if (mCurrentOperation != null) { - rval.resultCode = BLECommOperationResult.RESULT_BUSY; - } else { - if (bluetoothConnectionGatt.getService(serviceUUID) == null) { - // Catch if the service is not supported by the BLE device - rval.resultCode = BLECommOperationResult.RESULT_NONE; - aapsLogger.error(LTag.PUMPBTCOMM, "BT Device not supported"); - // TODO: 11/07/2016 UI update for user - // xyz rileyLinkServiceData.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.NoBluetoothAdapter); - } else { - BluetoothGattCharacteristic chara = bluetoothConnectionGatt.getService(serviceUUID) - .getCharacteristic(charaUUID); - // Tell Android that we want the notifications - bluetoothConnectionGatt.setCharacteristicNotification(chara, true); - List list = chara.getDescriptors(); - if (gattDebugEnabled) { - for (int i = 0; i < list.size(); i++) { - aapsLogger.debug(LTag.PUMPBTCOMM, "Found descriptor: " + list.get(i).toString()); - } - } - BluetoothGattDescriptor descr = list.get(0); - // Tell the remote device to send the notifications - mCurrentOperation = new DescriptorWriteOperation(aapsLogger, bluetoothConnectionGatt, descr, - BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); - mCurrentOperation.execute(this); - if (mCurrentOperation.timedOut) { - rval.resultCode = BLECommOperationResult.RESULT_TIMEOUT; - } else if (mCurrentOperation.interrupted) { - rval.resultCode = BLECommOperationResult.RESULT_INTERRUPTED; - } else { - rval.resultCode = BLECommOperationResult.RESULT_SUCCESS; - } - } - mCurrentOperation = null; - gattOperationSema.release(); - } - } else { - aapsLogger.error(LTag.PUMPBTCOMM, "setNotification_blocking: not configured!"); - rval.resultCode = BLECommOperationResult.RESULT_NOT_CONFIGURED; - } - return rval; - } - - - // call from main - BLECommOperationResult writeCharacteristic_blocking(UUID serviceUUID, UUID charaUUID, byte[] value) { - BLECommOperationResult rval = new BLECommOperationResult(); - if (bluetoothConnectionGatt != null) { - rval.value = value; - try { - gattOperationSema.acquire(); - SystemClock.sleep(1); // attempting to yield thread, to make sequence of events easier to follow - } catch (InterruptedException e) { - aapsLogger.error(LTag.PUMPBTCOMM, "writeCharacteristic_blocking: interrupted waiting for gattOperationSema"); - return rval; - } - - if (mCurrentOperation != null) { - rval.resultCode = BLECommOperationResult.RESULT_BUSY; - } else { - if (bluetoothConnectionGatt.getService(serviceUUID) == null) { - // Catch if the service is not supported by the BLE device - // GGW: Tue Jul 12 01:14:01 UTC 2016: This can also happen if the - // app that created the bluetoothConnectionGatt has been destroyed/created, - // e.g. when the user switches from portrait to landscape. - rval.resultCode = BLECommOperationResult.RESULT_NONE; - aapsLogger.error(LTag.PUMPBTCOMM, "BT Device not supported"); - // TODO: 11/07/2016 UI update for user - // xyz rileyLinkServiceData.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.NoBluetoothAdapter); - } else { - BluetoothGattCharacteristic chara = bluetoothConnectionGatt.getService(serviceUUID) - .getCharacteristic(charaUUID); - mCurrentOperation = new CharacteristicWriteOperation(aapsLogger, bluetoothConnectionGatt, chara, value); - mCurrentOperation.execute(this); - if (mCurrentOperation.timedOut) { - rval.resultCode = BLECommOperationResult.RESULT_TIMEOUT; - } else if (mCurrentOperation.interrupted) { - rval.resultCode = BLECommOperationResult.RESULT_INTERRUPTED; - } else { - rval.resultCode = BLECommOperationResult.RESULT_SUCCESS; - } - } - mCurrentOperation = null; - gattOperationSema.release(); - } - } else { - aapsLogger.error(LTag.PUMPBTCOMM, "writeCharacteristic_blocking: not configured!"); - rval.resultCode = BLECommOperationResult.RESULT_NOT_CONFIGURED; - } - return rval; - } - - - BLECommOperationResult readCharacteristic_blocking(UUID serviceUUID, UUID charaUUID) { - BLECommOperationResult rval = new BLECommOperationResult(); - if (bluetoothConnectionGatt != null) { - try { - gattOperationSema.acquire(); - SystemClock.sleep(1); // attempting to yield thread, to make sequence of events easier to follow - } catch (InterruptedException e) { - aapsLogger.error(LTag.PUMPBTCOMM, "readCharacteristic_blocking: Interrupted waiting for gattOperationSema"); - return rval; - } - if (mCurrentOperation != null) { - rval.resultCode = BLECommOperationResult.RESULT_BUSY; - } else { - if (bluetoothConnectionGatt.getService(serviceUUID) == null) { - // Catch if the service is not supported by the BLE device - rval.resultCode = BLECommOperationResult.RESULT_NONE; - aapsLogger.error(LTag.PUMPBTCOMM, "BT Device not supported"); - // TODO: 11/07/2016 UI update for user - // xyz rileyLinkServiceData.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.NoBluetoothAdapter); - } else { - BluetoothGattCharacteristic chara = bluetoothConnectionGatt.getService(serviceUUID).getCharacteristic( - charaUUID); - mCurrentOperation = new CharacteristicReadOperation(aapsLogger, bluetoothConnectionGatt, chara); - mCurrentOperation.execute(this); - if (mCurrentOperation.timedOut) { - rval.resultCode = BLECommOperationResult.RESULT_TIMEOUT; - } else if (mCurrentOperation.interrupted) { - rval.resultCode = BLECommOperationResult.RESULT_INTERRUPTED; - } else { - rval.resultCode = BLECommOperationResult.RESULT_SUCCESS; - rval.value = mCurrentOperation.getValue(); - } - } - } - mCurrentOperation = null; - gattOperationSema.release(); - } else { - aapsLogger.error(LTag.PUMPBTCOMM, "readCharacteristic_blocking: not configured!"); - rval.resultCode = BLECommOperationResult.RESULT_NOT_CONFIGURED; - } - return rval; - } - - - private String getGattStatusMessage(final int status) { - final String statusMessage; - if (status == BluetoothGatt.GATT_SUCCESS) { - statusMessage = "SUCCESS"; - } else if (status == BluetoothGatt.GATT_FAILURE) { - statusMessage = "FAILED"; - } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) { - statusMessage = "NOT PERMITTED"; - } else if (status == 133) { - statusMessage = "Found the strange 133 bug"; - } else { - statusMessage = "UNKNOWN (" + status + ")"; - } - - return statusMessage; - } - - public void setRileyLinkDevice(BluetoothDevice device) { - this.rileyLinkDevice = device; - } - - public BluetoothAdapter getBluetoothAdapter() { - return bluetoothAdapter; - } -} diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.kt new file mode 100644 index 0000000000..a178605b62 --- /dev/null +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.kt @@ -0,0 +1,447 @@ +package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble + +import android.annotation.SuppressLint +import android.bluetooth.* +import android.content.Context +import android.os.SystemClock +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.GattAttributes +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.device.OrangeLinkImpl +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.BLECommOperation +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.BLECommOperationResult +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.CharacteristicReadOperation +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.CharacteristicWriteOperation +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.DescriptorWriteOperation +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkError +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.ThreadUtil +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.logging.LTag +import info.nightscout.shared.sharedPreferences.SP +import org.apache.commons.lang3.StringUtils +import java.util.* +import java.util.concurrent.Semaphore +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Created by geoff on 5/26/16. + * Added: State handling, configuration of RF for different configuration ranges, connection handling + */ +@Singleton +class RileyLinkBLE @Inject constructor(private val context: Context) { + + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var rileyLinkServiceData: RileyLinkServiceData + @Inject lateinit var rileyLinkUtil: RileyLinkUtil + @Inject lateinit var sp: SP + @Inject lateinit var orangeLink: OrangeLinkImpl + + private val gattDebugEnabled = true + private var manualDisconnect = false + val bluetoothAdapter: BluetoothAdapter = BluetoothAdapter.getDefaultAdapter() + private val bluetoothGattCallback: BluetoothGattCallback + var rileyLinkDevice: BluetoothDevice? = null + private var bluetoothConnectionGatt: BluetoothGatt? = null + private var mCurrentOperation: BLECommOperation? = null + private val gattOperationSema = Semaphore(1, true) + private var radioResponseCountNotified: Runnable? = null + var isConnected = false + private set + + @Inject fun onInit() { + //aapsLogger.debug(LTag.PUMPBTCOMM, "BT Adapter: " + this.bluetoothAdapter); + orangeLink.rileyLinkBLE = this + } + + private fun isAnyRileyLinkServiceFound(service: BluetoothGattService): Boolean { + val found = GattAttributes.isRileyLink(service.uuid) + if (found) return true + else + for (serviceI in service.includedServices) { + if (isAnyRileyLinkServiceFound(serviceI)) return true + orangeLink.checkIsOrange(serviceI.uuid) + } + return false + } + + fun debugService(service: BluetoothGattService, indentCount: Int, stringBuilder: StringBuilder) { + val indentString = StringUtils.repeat(' ', indentCount) + if (gattDebugEnabled) { + val uuidServiceString = service.uuid.toString() + + stringBuilder.append(indentString) + stringBuilder.append(GattAttributes.lookup(uuidServiceString, "Unknown service")) + stringBuilder.append(" ($uuidServiceString)") + for (character in service.characteristics) { + val uuidCharacteristicString = character.uuid.toString() + stringBuilder.append("\n ") + stringBuilder.append(indentString) + stringBuilder.append(" - " + GattAttributes.lookup(uuidCharacteristicString, "Unknown Characteristic")) + stringBuilder.append(" ($uuidCharacteristicString)") + } + stringBuilder.append("\n\n") + + //aapsLogger.warn(LTag.PUMPBTCOMM, stringBuilder.toString()); + for (serviceI in service.includedServices) { + debugService(serviceI, indentCount + 4, stringBuilder) + } + } + } + + fun registerRadioResponseCountNotification(notifier: Runnable?) { + radioResponseCountNotified = notifier + } + + fun discoverServices(): Boolean { + // shouldn't happen, but if it does we exit + bluetoothConnectionGatt ?: return false + + return if (bluetoothConnectionGatt?.discoverServices() == true) { + aapsLogger.warn(LTag.PUMPBTCOMM, "Starting to discover GATT Services.") + true + } else { + aapsLogger.error(LTag.PUMPBTCOMM, "Cannot discover GATT Services.") + false + } + } + + fun enableNotifications(): Boolean { + val result = setNotificationBlocking(UUID.fromString(GattAttributes.SERVICE_RADIO), UUID.fromString(GattAttributes.CHARA_RADIO_RESPONSE_COUNT)) + if (result.resultCode != BLECommOperationResult.RESULT_SUCCESS) { + aapsLogger.error(LTag.PUMPBTCOMM, "Error setting response count notification") + return false + } + return if (rileyLinkServiceData.isOrange) orangeLink.enableNotifications() + else true + } + + fun findRileyLink(rileyLinkAddress: String) { + aapsLogger.debug(LTag.PUMPBTCOMM, "RileyLink address: $rileyLinkAddress") + // Must verify that this is a valid MAC, or crash. + //macAddress = RileyLinkAddress; + val useScanning = sp.getBoolean(RileyLinkConst.Prefs.OrangeUseScanning, false) + if (useScanning) { + aapsLogger.debug(LTag.PUMPBTCOMM, "Start scan for OrangeLink device.") + orangeLink.startScan() + } else { + rileyLinkDevice = bluetoothAdapter.getRemoteDevice(rileyLinkAddress) + // if this succeeds, we get a connection state change callback? + if (rileyLinkDevice != null) connectGattInternal() + else aapsLogger.error(LTag.PUMPBTCOMM, "RileyLink device not found with address: $rileyLinkAddress") + } + } + + fun connectGatt() { + val useScanning = sp.getBoolean(RileyLinkConst.Prefs.OrangeUseScanning, false) + if (useScanning) { + aapsLogger.debug(LTag.PUMPBTCOMM, "Start scan for OrangeLink device.") + orangeLink.startScan() + } else { + connectGattInternal() + } + } + + // This function must be run on UI thread. + @SuppressLint("HardwareIds") + fun connectGattInternal() { + if (rileyLinkDevice == null) { + aapsLogger.error(LTag.PUMPBTCOMM, "RileyLink device is null, can't do connectGatt.") + return + } + bluetoothConnectionGatt = rileyLinkDevice?.connectGatt(context, true, bluetoothGattCallback) + // , BluetoothDevice.TRANSPORT_LE + if (bluetoothConnectionGatt == null) + aapsLogger.error(LTag.PUMPBTCOMM, "Failed to connect to Bluetooth Low Energy device at " + bluetoothAdapter.address) + else { + if (gattDebugEnabled) aapsLogger.debug(LTag.PUMPBTCOMM, "Gatt Connected.") + val deviceName = bluetoothConnectionGatt?.device?.name + // Update stored name upon connecting (also for backwards compatibility for device where a name was not yet stored) + if (StringUtils.isNotEmpty(deviceName)) sp.putString(RileyLinkConst.Prefs.RileyLinkName, deviceName!!) + else sp.remove(RileyLinkConst.Prefs.RileyLinkName) + rileyLinkServiceData.rileyLinkName = deviceName + rileyLinkServiceData.rileyLinkAddress = bluetoothConnectionGatt?.device?.address + } + } + + fun disconnect() { + isConnected = false + aapsLogger.warn(LTag.PUMPBTCOMM, "Closing GATT connection") + // Close old connection + if (bluetoothConnectionGatt != null) { + // Not sure if to disconnect or to close first.. + bluetoothConnectionGatt?.disconnect() + manualDisconnect = true + } + } + + fun close() { + bluetoothConnectionGatt?.close() + bluetoothConnectionGatt = null + } + + fun setNotificationBlocking(serviceUUID: UUID?, charaUUID: UUID?): BLECommOperationResult { + val retValue = BLECommOperationResult() + if (bluetoothConnectionGatt == null) { + aapsLogger.error(LTag.PUMPBTCOMM, "setNotification_blocking: not configured!") + retValue.resultCode = BLECommOperationResult.RESULT_NOT_CONFIGURED + return retValue + } + gattOperationSema.acquire() + SystemClock.sleep(1) // attempting to yield thread, to make sequence of events easier to follow + if (mCurrentOperation != null) retValue.resultCode = BLECommOperationResult.RESULT_BUSY + else { + if (bluetoothConnectionGatt?.getService(serviceUUID) == null) { + // Catch if the service is not supported by the BLE device + retValue.resultCode = BLECommOperationResult.RESULT_NONE + aapsLogger.error(LTag.PUMPBTCOMM, "BT Device not supported") + // TODO: 11/07/2016 UI update for user + // xyz rileyLinkServiceData.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.NoBluetoothAdapter); + } else { + val chara = bluetoothConnectionGatt?.getService(serviceUUID)?.getCharacteristic(charaUUID) ?: return retValue.apply { resultCode = BLECommOperationResult.RESULT_NONE } + // Tell Android that we want the notifications + bluetoothConnectionGatt?.setCharacteristicNotification(chara, true) + val list = chara.descriptors + if (gattDebugEnabled) for (i in list.indices) aapsLogger.debug(LTag.PUMPBTCOMM, "Found descriptor: " + list[i].toString()) + // Tell the remote device to send the notifications + mCurrentOperation = DescriptorWriteOperation(aapsLogger, bluetoothConnectionGatt, list[0], BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) + mCurrentOperation?.execute(this) + when { + mCurrentOperation?.timedOut == true -> retValue.resultCode = BLECommOperationResult.RESULT_TIMEOUT + mCurrentOperation?.interrupted == true -> retValue.resultCode = BLECommOperationResult.RESULT_INTERRUPTED + else -> retValue.resultCode = BLECommOperationResult.RESULT_SUCCESS + } + } + mCurrentOperation = null + gattOperationSema.release() + } + return retValue + } + + // call from main + fun writeCharacteristicBlocking(serviceUUID: UUID?, charaUUID: UUID?, value: ByteArray?): BLECommOperationResult { + val retValue = BLECommOperationResult() + if (bluetoothConnectionGatt == null) { + aapsLogger.error(LTag.PUMPBTCOMM, "writeCharacteristic_blocking: not configured!") + retValue.resultCode = BLECommOperationResult.RESULT_NOT_CONFIGURED + return retValue + } + retValue.value = value + gattOperationSema.acquire() + SystemClock.sleep(1) // attempting to yield thread, to make sequence of events easier to follow + if (mCurrentOperation != null) retValue.resultCode = BLECommOperationResult.RESULT_BUSY + else { + if (bluetoothConnectionGatt?.getService(serviceUUID) == null) { + // Catch if the service is not supported by the BLE device + // GGW: Tue Jul 12 01:14:01 UTC 2016: This can also happen if the + // app that created the bluetoothConnectionGatt has been destroyed/created, + // e.g. when the user switches from portrait to landscape. + retValue.resultCode = BLECommOperationResult.RESULT_NONE + aapsLogger.error(LTag.PUMPBTCOMM, "BT Device not supported") + // TODO: 11/07/2016 UI update for user + // xyz rileyLinkServiceData.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.NoBluetoothAdapter); + } else { + val chara = bluetoothConnectionGatt?.getService(serviceUUID)?.getCharacteristic(charaUUID) ?: return retValue.apply { resultCode = BLECommOperationResult.RESULT_NOT_CONFIGURED } + mCurrentOperation = CharacteristicWriteOperation(aapsLogger, bluetoothConnectionGatt, chara, value) + mCurrentOperation?.execute(this) + when { + mCurrentOperation?.timedOut == true -> retValue.resultCode = BLECommOperationResult.RESULT_TIMEOUT + mCurrentOperation?.interrupted == true -> retValue.resultCode = BLECommOperationResult.RESULT_INTERRUPTED + else -> retValue.resultCode = BLECommOperationResult.RESULT_SUCCESS + } + } + mCurrentOperation = null + gattOperationSema.release() + } + return retValue + } + + fun readCharacteristicBlocking(serviceUUID: UUID?, charaUUID: UUID?): BLECommOperationResult { + val retValue = BLECommOperationResult() + if (bluetoothConnectionGatt == null) { + aapsLogger.error(LTag.PUMPBTCOMM, "readCharacteristic_blocking: not configured!") + retValue.resultCode = BLECommOperationResult.RESULT_NOT_CONFIGURED + return retValue + } + + gattOperationSema.acquire() + SystemClock.sleep(1) // attempting to yield thread, to make sequence of events easier to follow + if (mCurrentOperation != null) retValue.resultCode = BLECommOperationResult.RESULT_BUSY + else { + if (bluetoothConnectionGatt?.getService(serviceUUID) == null) { + // Catch if the service is not supported by the BLE device + retValue.resultCode = BLECommOperationResult.RESULT_NONE + aapsLogger.error(LTag.PUMPBTCOMM, "BT Device not supported") + // TODO: 11/07/2016 UI update for user + // xyz rileyLinkServiceData.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.NoBluetoothAdapter); + } else { + val chara = bluetoothConnectionGatt?.getService(serviceUUID)?.getCharacteristic(charaUUID) ?: return retValue.apply { resultCode = BLECommOperationResult.RESULT_NOT_CONFIGURED } + mCurrentOperation = CharacteristicReadOperation(aapsLogger, bluetoothConnectionGatt, chara) + mCurrentOperation?.execute(this) + when { + mCurrentOperation?.timedOut == true -> retValue.resultCode = BLECommOperationResult.RESULT_TIMEOUT + mCurrentOperation?.interrupted == true -> retValue.resultCode = BLECommOperationResult.RESULT_INTERRUPTED + + else -> { + retValue.resultCode = BLECommOperationResult.RESULT_SUCCESS + retValue.value = mCurrentOperation?.value + } + } + } + } + mCurrentOperation = null + gattOperationSema.release() + + return retValue + } + + private fun getGattStatusMessage(status: Int): String = + when (status) { + BluetoothGatt.GATT_SUCCESS -> "SUCCESS" + BluetoothGatt.GATT_FAILURE -> "FAILED" + BluetoothGatt.GATT_WRITE_NOT_PERMITTED -> "NOT PERMITTED" + 133 -> "Found the strange 133 bug" + else -> "UNKNOWN ($status)" + } + + init { + //orangeLink.rileyLinkBLE = this; + bluetoothGattCallback = object : BluetoothGattCallback() { + override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) { + super.onCharacteristicChanged(gatt, characteristic) + if (gattDebugEnabled) { + aapsLogger.debug(LTag.PUMPBTCOMM, "${ThreadUtil.sig()}onCharacteristicChanged ${GattAttributes.lookup(characteristic.uuid)} ${ByteUtil.getHex(characteristic.value)}") + if (characteristic.uuid == UUID.fromString(GattAttributes.CHARA_RADIO_RESPONSE_COUNT)) + aapsLogger.debug(LTag.PUMPBTCOMM, "Response Count is " + ByteUtil.shortHexString(characteristic.value)) + } + if (characteristic.uuid == UUID.fromString(GattAttributes.CHARA_RADIO_RESPONSE_COUNT)) + radioResponseCountNotified?.run() + orangeLink.onCharacteristicChanged(characteristic) + } + + override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { + super.onCharacteristicRead(gatt, characteristic, status) + val statusMessage = getGattStatusMessage(status) + if (gattDebugEnabled) + aapsLogger.debug(LTag.PUMPBTCOMM, "${ThreadUtil.sig()}onCharacteristicRead (${GattAttributes.lookup(characteristic.uuid)}) $statusMessage:${ByteUtil.getHex(characteristic.value)}") + mCurrentOperation?.gattOperationCompletionCallback(characteristic.uuid, characteristic.value) + } + + override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { + super.onCharacteristicWrite(gatt, characteristic, status) + val uuidString = GattAttributes.lookup(characteristic.uuid) + if (gattDebugEnabled) + aapsLogger.debug(LTag.PUMPBTCOMM, "${ThreadUtil.sig()}onCharacteristicWrite ${getGattStatusMessage(status)} $uuidString ${ByteUtil.shortHexString(characteristic.value)}") + mCurrentOperation?.gattOperationCompletionCallback(characteristic.uuid, characteristic.value) + } + + override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { + super.onConnectionStateChange(gatt, status, newState) + + // https://github.com/NordicSemiconductor/puck-central-android/blob/master/PuckCentral/app/src/main/java/no/nordicsemi/puckcentral/bluetooth/gatt/GattManager.java#L117 + if (status == 133) { + aapsLogger.error(LTag.PUMPBTCOMM, "Got the status 133 bug, closing gatt") + disconnect() + SystemClock.sleep(500) + return + } + if (gattDebugEnabled) { + val stateMessage: String = when (newState) { + BluetoothProfile.STATE_CONNECTED -> "CONNECTED" + BluetoothProfile.STATE_CONNECTING -> "CONNECTING" + BluetoothProfile.STATE_DISCONNECTED -> "DISCONNECTED" + BluetoothProfile.STATE_DISCONNECTING -> "DISCONNECTING" + else -> "UNKNOWN newState ($newState)" + } + + aapsLogger.warn(LTag.PUMPBTCOMM, "onConnectionStateChange " + getGattStatusMessage(status) + " " + stateMessage) + } + if (newState == BluetoothProfile.STATE_CONNECTED) { + if (status == BluetoothGatt.GATT_SUCCESS) rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.BluetoothConnected, context) + else aapsLogger.debug(LTag.PUMPBTCOMM, "BT State connected, GATT status ${status} (${getGattStatusMessage(status)})") + } else if (newState == BluetoothProfile.STATE_CONNECTING || newState == BluetoothProfile.STATE_DISCONNECTING) { + aapsLogger.debug(LTag.PUMPBTCOMM, "We are in ${if (status == BluetoothProfile.STATE_CONNECTING) "Connecting" else "Disconnecting"} state.") + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkDisconnected, context) + if (manualDisconnect) close() + aapsLogger.warn(LTag.PUMPBTCOMM, "RileyLink Disconnected.") + } else { + aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Some other state: (status=%d, newState=%d)", status, newState)) + } + } + + override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) { + super.onDescriptorWrite(gatt, descriptor, status) + if (gattDebugEnabled) + aapsLogger.warn(LTag.PUMPBTCOMM, "onDescriptorWrite ${GattAttributes.lookup(descriptor.uuid)} ${getGattStatusMessage(status)} written: ${ByteUtil.getHex(descriptor.value)}") + mCurrentOperation?.gattOperationCompletionCallback(descriptor.uuid, descriptor.value) + } + + override fun onDescriptorRead(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) { + super.onDescriptorRead(gatt, descriptor, status) + mCurrentOperation?.gattOperationCompletionCallback(descriptor.uuid, descriptor.value) + if (gattDebugEnabled) + aapsLogger.warn(LTag.PUMPBTCOMM, "onDescriptorRead " + getGattStatusMessage(status) + " status " + descriptor) + } + + override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) { + super.onMtuChanged(gatt, mtu, status) + if (gattDebugEnabled) + aapsLogger.warn(LTag.PUMPBTCOMM, "onMtuChanged $mtu status $status") + } + + override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) { + super.onReadRemoteRssi(gatt, rssi, status) + if (gattDebugEnabled) + aapsLogger.warn(LTag.PUMPBTCOMM, "onReadRemoteRssi " + getGattStatusMessage(status) + ": " + rssi) + } + + override fun onReliableWriteCompleted(gatt: BluetoothGatt, status: Int) { + super.onReliableWriteCompleted(gatt, status) + if (gattDebugEnabled) + aapsLogger.warn(LTag.PUMPBTCOMM, "onReliableWriteCompleted status $status") + } + + override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { + super.onServicesDiscovered(gatt, status) + if (status == BluetoothGatt.GATT_SUCCESS) { + val services = gatt.services + var rileyLinkFound = false + orangeLink.resetOrangeLinkData() + val stringBuilder = StringBuilder("RileyLink Device Debug\n") + for (service in services) { + val uuidService = service.uuid + if (isAnyRileyLinkServiceFound(service)) { + rileyLinkFound = true + } + if (gattDebugEnabled) { + debugService(service, 0, stringBuilder) + } + orangeLink.checkIsOrange(uuidService) + } + if (gattDebugEnabled) { + aapsLogger.warn(LTag.PUMPBTCOMM, stringBuilder.toString()) + aapsLogger.warn(LTag.PUMPBTCOMM, "onServicesDiscovered " + getGattStatusMessage(status)) + } + aapsLogger.info(LTag.PUMPBTCOMM, "Gatt device is RileyLink device: $rileyLinkFound") + if (rileyLinkFound) { + isConnected = true + rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkReady, context) + } else { + isConnected = false + rileyLinkServiceData.setServiceState( + RileyLinkServiceState.RileyLinkError, + RileyLinkError.DeviceIsNotRileyLink + ) + } + } else { + aapsLogger.debug(LTag.PUMPBTCOMM, "onServicesDiscovered " + getGattStatusMessage(status)) + rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkGattFailed, context) + } + } + } + } +} \ No newline at end of file diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/device/OrangeLinkImpl.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/device/OrangeLinkImpl.kt index ba9cb795e0..0e8f3cf6d7 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/device/OrangeLinkImpl.kt +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/device/OrangeLinkImpl.kt @@ -67,7 +67,7 @@ class OrangeLinkImpl @Inject constructor( fun enableNotifications(): Boolean { aapsLogger.info(LTag.PUMPBTCOMM, "OrangeLinkImpl::enableNotifications") - val result: BLECommOperationResult = rileyLinkBLE.setNotification_blocking( + val result: BLECommOperationResult = rileyLinkBLE.setNotificationBlocking( UUID.fromString(GattAttributes.SERVICE_RADIO_ORANGE), // UUID.fromString(GattAttributes.CHARA_NOTIFICATION_ORANGE) ) @@ -156,7 +156,7 @@ class OrangeLinkImpl @Inject constructor( fun stopScan() { handler.removeMessages(TIME_OUT_WHAT) - val bluetoothAdapter = rileyLinkBLE.bluetoothAdapter ?: return + val bluetoothAdapter = rileyLinkBLE.bluetoothAdapter try { val bluetoothLeScanner: BluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner @@ -183,9 +183,7 @@ class OrangeLinkImpl @Inject constructor( private fun isBluetoothAvailable(): Boolean { val bluetoothAdapter = rileyLinkBLE.bluetoothAdapter - return bluetoothAdapter != null && - bluetoothAdapter.isEnabled && - bluetoothAdapter.state == BluetoothAdapter.STATE_ON + return bluetoothAdapter.isEnabled && bluetoothAdapter.state == BluetoothAdapter.STATE_ON } companion object {