From 2a14d60beed923a71f435efea9624a7f2f867232 Mon Sep 17 00:00:00 2001 From: AdrianLxM Date: Wed, 24 Feb 2021 20:12:29 +0100 Subject: [PATCH] kotlin a bit more idiomatic after conversion from Java --- .../omnipod/dash/driver/comm/BleManager.kt | 65 ++++++------------- .../dash/driver/comm/CharacteristicType.kt | 12 ++-- .../dash/driver/comm/ServiceDiscoverer.kt | 19 +++--- .../driver/comm/callbacks/BleCommCallbacks.kt | 58 ++++++++--------- .../CharacteristicWriteConfirmation.kt | 6 +- .../driver/comm/command/BleCommandType.kt | 11 +--- .../comm/exceptions/CouldNotConfirmWrite.kt | 9 +-- .../ScanFailFoundTooManyException.kt | 8 +-- .../pump/omnipod/dash/driver/comm/io/BleIO.kt | 8 +-- .../dash/driver/comm/scan/PodScanner.kt | 2 +- .../dash/driver/comm/scan/ScanCollector.kt | 7 +- 11 files changed, 78 insertions(+), 127 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/BleManager.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/BleManager.kt index 630d57c1b9..a227adab18 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/BleManager.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/BleManager.kt @@ -1,68 +1,49 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm - -import javax.inject.Singleton -import javax.inject.Inject -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashCommunicationManager import android.bluetooth.BluetoothAdapter -import android.bluetooth.BluetoothManager -import info.nightscout.androidaps.logging.AAPSLogger -import android.bluetooth.BluetoothGatt -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO -import kotlin.Throws -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.ScanFailException -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.FailedToConnectException -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotSendBleException -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.BleIOBusyException -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmWrite -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotEnableNotifications -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.DescriptorNotFoundException -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmDescriptorWriteException -import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan.PodScanner import android.bluetooth.BluetoothDevice -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.BleManager +import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothProfile -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ServiceDiscoverer -import android.bluetooth.BluetoothGattCharacteristic import android.content.Context +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandHello +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.* +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan.PodScanner import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque import java.util.concurrent.TimeoutException +import javax.inject.Inject +import javax.inject.Singleton @Singleton -class BleManager @Inject constructor(private val context: Context) : OmnipodDashCommunicationManager { +class BleManager @Inject constructor(private val context: Context, private val aapsLogger: AAPSLogger) : OmnipodDashCommunicationManager { - private val bluetoothAdapter: BluetoothAdapter - private val bluetoothManager: BluetoothManager + private val bluetoothManager: BluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager + private val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter - @Inject lateinit var aapsLogger: AAPSLogger - private var podAddress: String? = null - private var gatt: BluetoothGatt? = null - private var bleio: BleIO? = null @Throws(InterruptedException::class, ScanFailException::class, FailedToConnectException::class, CouldNotSendBleException::class, BleIOBusyException::class, TimeoutException::class, CouldNotConfirmWrite::class, CouldNotEnableNotifications::class, DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class) fun activateNewPod() { aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation") val podScanner = PodScanner(aapsLogger, bluetoothAdapter) - podAddress = podScanner.scanForPod(PodScanner.SCAN_FOR_SERVICE_UUID, PodScanner.POD_ID_NOT_ACTIVATED).scanResult.device.address + val podAddress = podScanner.scanForPod(PodScanner.SCAN_FOR_SERVICE_UUID, PodScanner.POD_ID_NOT_ACTIVATED).scanResult.device.address // For tests: this.podAddress = "B8:27:EB:1D:7E:BB"; - connect() + connect(podAddress) } @Throws(FailedToConnectException::class, CouldNotSendBleException::class, InterruptedException::class, BleIOBusyException::class, TimeoutException::class, CouldNotConfirmWrite::class, CouldNotEnableNotifications::class, DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class) - fun connect() { + private fun connect(podAddress: String) { // TODO: locking? val podDevice = bluetoothAdapter.getRemoteDevice(podAddress) - var incomingPackets: Map> = + val incomingPackets: Map> = mapOf(CharacteristicType.CMD to LinkedBlockingDeque(), CharacteristicType.DATA to LinkedBlockingDeque()); val bleCommCallbacks = BleCommCallbacks(aapsLogger, incomingPackets) - aapsLogger.debug(LTag.PUMPBTCOMM, "Connecting to " + podAddress) + aapsLogger.debug(LTag.PUMPBTCOMM, "Connecting to $podAddress") var autoConnect = true if (BuildConfig.DEBUG) { autoConnect = false @@ -70,8 +51,6 @@ class BleManager @Inject constructor(private val context: Context) : OmnipodDash // it's easier to start testing from scratch on each run. } val gatt = podDevice.connectGatt(context, autoConnect, bleCommCallbacks, BluetoothDevice.TRANSPORT_LE) - this.gatt = gatt - bleCommCallbacks.waitForConnection(CONNECT_TIMEOUT_MS) val connectionState = bluetoothManager.getConnectionState(podDevice, BluetoothProfile.GATT) aapsLogger.debug(LTag.PUMPBTCOMM, "GATT connection state: $connectionState") @@ -80,10 +59,10 @@ class BleManager @Inject constructor(private val context: Context) : OmnipodDash } val discoverer = ServiceDiscoverer(aapsLogger, gatt, bleCommCallbacks) val chars = discoverer.discoverServices() - bleio = BleIO(aapsLogger, chars, incomingPackets, gatt, bleCommCallbacks) + val bleIO = BleIO(aapsLogger, chars, incomingPackets, gatt, bleCommCallbacks) aapsLogger.debug(LTag.PUMPBTCOMM, "Saying hello to the pod") - bleio!!.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandHello(CONTROLLER_ID).asByteArray()) - bleio!!.readyToRead() + bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandHello(CONTROLLER_ID).asByteArray()) + bleIO.readyToRead() } companion object { @@ -92,8 +71,4 @@ class BleManager @Inject constructor(private val context: Context) : OmnipodDash private const val CONTROLLER_ID = 4242 // TODO read from preferences or somewhere else. } - init { - bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager - bluetoothAdapter = bluetoothManager.adapter - } } \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/CharacteristicType.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/CharacteristicType.kt index 600e4ba769..a68ccba448 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/CharacteristicType.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/CharacteristicType.kt @@ -14,13 +14,9 @@ enum class CharacteristicType(val value: String) { companion object { - @JvmStatic fun byValue(value: String): CharacteristicType { - for (type in values()) { - if (type.value == value) { - return type - } - } - throw IllegalArgumentException("Unknown Characteristic Type: $value") - } + @JvmStatic + fun byValue(value: String): CharacteristicType = + values().firstOrNull { it.value == value } + ?: throw IllegalArgumentException("Unknown Characteristic Type: $value") } } \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt index 85694a213a..ccf7298a6e 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt @@ -22,26 +22,25 @@ class ServiceDiscoverer(private val logger: AAPSLogger, private val gatt: Blueto gatt.discoverServices() bleCallbacks.waitForServiceDiscovery(DISCOVER_SERVICES_TIMEOUT_MS) logger.debug(LTag.PUMPBTCOMM, "Services discovered") - val service = gatt.getService( - uuidFromString(SERVICE_UUID)) + val service = gatt.getService(SERVICE_UUID.toUuid()) ?: throw ServiceNotFoundException(SERVICE_UUID) val cmdChar = service.getCharacteristic(CharacteristicType.CMD.uUID) ?: throw CharacteristicNotFoundException(CharacteristicType.CMD.value) - val dataChar = service.getCharacteristic(CharacteristicType.DATA.uUID) + val dataChar = service.getCharacteristic(CharacteristicType.DATA.uUID) // TODO: this is never used ?: throw CharacteristicNotFoundException(CharacteristicType.DATA.value) var chars = mapOf(CharacteristicType.CMD to cmdChar, CharacteristicType.DATA to dataChar) return chars } + + private fun String.toUuid(): UUID = UUID( + BigInteger(replace("-", "").substring(0, 16), 16).toLong(), + BigInteger(replace("-", "").substring(16), 16).toLong() + ) + companion object { private const val SERVICE_UUID = "1a7e-4024-e3ed-4464-8b7e-751e03d0dc5f" private const val DISCOVER_SERVICES_TIMEOUT_MS = 5000 - private fun uuidFromString(s: String): UUID { - return UUID( - BigInteger(s.replace("-", "").substring(0, 16), 16).toLong(), - BigInteger(s.replace("-", "").substring(16), 16).toLong() - ) - } } -} \ No newline at end of file +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt index 1998d9b307..e6d9dd545e 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt @@ -11,21 +11,19 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Characte import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType.Companion.byValue import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmDescriptorWriteException import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmWrite -import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.CountDownLatch import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException -class BleCommCallbacks(aapsLogger: AAPSLogger, incomingPackets: Map>) : BluetoothGattCallback() { +class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingPackets: Map>) : BluetoothGattCallback() { + + private val serviceDiscoveryComplete: CountDownLatch = CountDownLatch(1) + private val connected: CountDownLatch = CountDownLatch(1) + private val writeQueue: BlockingQueue = LinkedBlockingQueue(1) + private val descriptorWriteQueue: BlockingQueue = LinkedBlockingQueue(1) - private val serviceDiscoveryComplete: CountDownLatch - private val connected: CountDownLatch - private val aapsLogger: AAPSLogger - private val incomingPackets: Map> - private val writeQueue: BlockingQueue - private val descriptorWriteQueue: BlockingQueue override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { super.onConnectionStateChange(gatt, status, newState) aapsLogger.debug(LTag.PUMPBTCOMM, "OnConnectionStateChange discovered with status/state$status/$newState") @@ -42,42 +40,53 @@ class BleCommCallbacks(aapsLogger: AAPSLogger, incomingPackets: Map confirmWritePayload(expectedPayload, received) + is CharacteristicWriteConfirmationError -> + aapsLogger.debug(LTag.PUMPBTCOMM, "Could not confirm write: status was ${received.status}") + } + + } + + private fun confirmWritePayload(expectedPayload: ByteArray, received: CharacteristicWriteConfirmationPayload) { + if (!expectedPayload.contentEquals(received.payload)) { aapsLogger.warn(LTag.PUMPBTCOMM, "Could not confirm write. Got " + received.payload + ".Excepted: " + expectedPayload + ". Status: " + received.status) - throw CouldNotConfirmWrite(expectedPayload, received.payload!!) + throw CouldNotConfirmWrite(expectedPayload, received.payload) } aapsLogger.debug(LTag.PUMPBTCOMM, "Confirmed write with value: " + received.payload) } override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { super.onCharacteristicWrite(gatt, characteristic, status) - var received: ByteArray? = null - if (status == BluetoothGatt.GATT_SUCCESS) { - received = characteristic.value + val writeConfirmation = if (status == BluetoothGatt.GATT_SUCCESS) { aapsLogger.debug(LTag.PUMPBTCOMM, "OnCharacteristicWrite value " + characteristic.getStringValue(0)) + CharacteristicWriteConfirmationPayload(characteristic.value, status) + } else { + CharacteristicWriteConfirmationError(status) } aapsLogger.debug(LTag.PUMPBTCOMM, "OnCharacteristicWrite with status/char/value " + - status + "/" + - byValue(characteristic.uuid.toString()) + "/" + - received) + status + "/" + byValue(characteristic.uuid.toString()) + "/" + characteristic.value) try { if (writeQueue.size > 0) { aapsLogger.warn(LTag.PUMPBTCOMM, "Write confirm queue should be empty. found: " + writeQueue.size) writeQueue.clear() } - val offered = writeQueue.offer(CharacteristicWriteConfirmation(received, status), WRITE_CONFIRM_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS) + val offered = writeQueue.offer(writeConfirmation, WRITE_CONFIRM_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS) if (!offered) { aapsLogger.warn(LTag.PUMPBTCOMM, "Received delayed write confirmation") } @@ -130,13 +139,4 @@ class BleCommCallbacks(aapsLogger: AAPSLogger, incomingPackets: Map?) : ScanFailException() { +class ScanFailFoundTooManyException(devices: List) : ScanFailException() { - private val devices: List + private val devices: List = ArrayList(devices) val discoveredDevices: List get() = Collections.unmodifiableList(devices) - - init { - this.devices = ArrayList(devices) - } } \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt index 7dfe2a44b4..397520820c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt @@ -14,7 +14,7 @@ import java.util.concurrent.TimeoutException class BleIO(private val aapsLogger: AAPSLogger, private val chars: Map, private val incomingPackets: Map>, private val gatt: BluetoothGatt, private val bleCommCallbacks: BleCommCallbacks) { - private var state: IOState + private var state: IOState = IOState.IDLE /*** * @@ -29,7 +29,7 @@ class BleIO(private val aapsLogger: AAPSLogger, private val chars: Map 1) { throw ScanFailFoundTooManyException(collected) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/ScanCollector.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/ScanCollector.kt index d37f714854..1164815970 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/ScanCollector.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/ScanCollector.kt @@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap class ScanCollector(private val logger: AAPSLogger, private val podID: Long) : ScanCallback() { // there could be different threads calling the onScanResult callback - private val found: ConcurrentHashMap + private val found: ConcurrentHashMap = ConcurrentHashMap() private var scanFailed = 0 override fun onScanResult(callbackType: Int, result: ScanResult) { // callbackType will be ALL @@ -31,7 +31,7 @@ class ScanCollector(private val logger: AAPSLogger, private val podID: Long) : S if (scanFailed != 0) { throw ScanFailException(scanFailed) } - logger.debug(LTag.PUMPBTCOMM, "ScanCollector looking for podID: " + podID) + logger.debug(LTag.PUMPBTCOMM, "ScanCollector looking for podID: $podID") for (result in found.values) { try { val device = BleDiscoveredDevice(result, podID) @@ -45,7 +45,4 @@ class ScanCollector(private val logger: AAPSLogger, private val podID: Long) : S return Collections.unmodifiableList(ret) } - init { - found = ConcurrentHashMap() - } } \ No newline at end of file