RileyLinkBLE -> kt

This commit is contained in:
Milos Kozak 2021-12-12 13:12:20 +01:00
parent 8d21e849ae
commit 8e6f39dbe7
5 changed files with 454 additions and 648 deletions

View file

@ -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);

View file

@ -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) {

View file

@ -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<BluetoothGattService> 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<BluetoothGattService> 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<BluetoothGattService> 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<BluetoothGattDescriptor> 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;
}
}

View file

@ -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)
}
}
}
}
}

View file

@ -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 {