From 8154e16c94deeaf03ffe17e2946dd5c5e2504c9f Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Tue, 9 Mar 2021 23:19:22 +0100 Subject: [PATCH] dash ble: add a separate method for activating a new pod So we can call it explicitly instead of activating a new pod on connect() --- .../dash/driver/OmnipodDashManagerImpl.kt | 16 ++- .../dash/driver/comm/OmnipodDashBleManager.kt | 2 + .../driver/comm/OmnipodDashBleManagerImpl.kt | 125 +++++++++++------- .../PodAlreadyActivatedException.kt | 4 + .../pump/omnipod/dash/driver/comm/io/BleIO.kt | 2 +- .../dash/driver/comm/session/Session.kt | 2 +- .../omnipod/dash/driver/event/PodEvent.kt | 9 +- 7 files changed, 99 insertions(+), 61 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/PodAlreadyActivatedException.kt diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt index 2e3e5f62d6..9fe2630d00 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt @@ -50,7 +50,12 @@ class OmnipodDashManagerImpl @Inject constructor( private val observeConnectToPod: Observable get() = Observable.defer { bleManager.connect() + } // TODO are these reasonable values? + + private val observeScanAndActivateNewPod: Observable + get() = Observable.defer { + bleManager.activateNewPod() } // TODO are these reasonable values? private fun observeSendProgramBolusCommand( @@ -172,7 +177,7 @@ class OmnipodDashManagerImpl @Inject constructor( override fun activatePodPart1(lowReservoirAlertTrigger: AlertTrigger.ReservoirVolumeTrigger?): Observable { return Observable.concat( observePodReadyForActivationPart1, - observeConnectToPod, + observeScanAndActivateNewPod, observeActivationPart1Commands(lowReservoirAlertTrigger) ).doOnComplete(ActivationProgressUpdater(ActivationProgress.PHASE_1_COMPLETED)) // TODO these would be common for any observable returned in a public function in this class @@ -407,15 +412,12 @@ class OmnipodDashManagerImpl @Inject constructor( when (event) { is PodEvent.AlreadyConnected -> { podStateManager.bluetoothAddress = event.bluetoothAddress - podStateManager.uniqueId = event.uniqueId } is PodEvent.BluetoothConnected -> { - podStateManager.bluetoothAddress = event.address } is PodEvent.Connected -> { - podStateManager.uniqueId = event.uniqueId } is PodEvent.CommandSent -> { @@ -427,7 +429,11 @@ class OmnipodDashManagerImpl @Inject constructor( handleResponse(event.response) } - else -> { + is PodEvent.Paired -> { + podStateManager.uniqueId = event.uniqueId.toLong() + } + + else -> { // Do nothing } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManager.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManager.kt index 11e808ba73..3dd9f9e174 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManager.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManager.kt @@ -13,5 +13,7 @@ interface OmnipodDashBleManager { fun connect(): Observable + fun activateNewPod(): Observable + fun disconnect() } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index c793c90cf4..9b553e9146 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -59,6 +59,7 @@ class OmnipodDashBleManagerImpl @Inject constructor( DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class ) + private fun connect(podDevice: BluetoothDevice): BleIO { val incomingPackets: Map> = mapOf( @@ -90,7 +91,6 @@ class OmnipodDashBleManagerImpl @Inject constructor( val keys = sessionKeys val mIO = msgIO if (keys == null || mIO == null) { - // TODO handle reconnects throw Exception("Not connected") } emitter.onNext(PodEvent.CommandSending(cmd)) @@ -142,75 +142,100 @@ class OmnipodDashBleManagerImpl @Inject constructor( ) override fun connect(): Observable = Observable.create { emitter -> - // TODO: when we are already connected, - // emit PodEvent.AlreadyConnected, complete the observable and return from this method try { - if (podState.bluetoothAddress == null) { - aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation") - val podScanner = PodScanner(aapsLogger, bluetoothAdapter) - emitter.onNext(PodEvent.Scanning) - - 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"; - podState.bluetoothAddress = podAddress - } - emitter.onNext(PodEvent.BluetoothConnecting) - val podAddress = podState.bluetoothAddress ?: throw FailedToConnectException("Lost connection") + val podAddress = podState.bluetoothAddress ?: throw FailedToConnectException("Missing bluetoothAddress, activate the pod first") // check if already connected val podDevice = bluetoothAdapter.getRemoteDevice(podAddress) val connectionState = bluetoothManager.getConnectionState(podDevice, BluetoothProfile.GATT) aapsLogger.debug(LTag.PUMPBTCOMM, "GATT connection state: $connectionState") - - emitter.onNext(PodEvent.BluetoothConnected(podAddress)) if (connectionState == BluetoothProfile.STATE_CONNECTED) { - podState.uniqueId ?: throw FailedToConnectException("Already connection and uniqueId is missing") - emitter.onNext(PodEvent.AlreadyConnected(podAddress, podState.uniqueId ?: 0)) + emitter.onNext(PodEvent.AlreadyConnected(podAddress)) emitter.onComplete() return@create } + emitter.onNext(PodEvent.BluetoothConnecting) if (msgIO != null) { disconnect() } - val bleIO = connect(podDevice) + val mIO = MessageIO(aapsLogger, bleIO) + msgIO = mIO + emitter.onNext(PodEvent.BluetoothConnected) + + emitter.onNext(PodEvent.EstablishingSession) + + establishSession(1.toByte()) + + emitter.onNext(PodEvent.Connected) + + emitter.onComplete() + } catch (ex: Exception) { + disconnect() + emitter.tryOnError(ex) + } + } + + private fun establishSession(msgSeq: Byte) { + val mIO = msgIO ?: throw FailedToConnectException("connection lost") + val ltk: ByteArray = podState.ltk ?: throw FailedToConnectException("Missing LTK, activate the pod first") + val myId = Id.fromInt(CONTROLLER_ID) + val uniqueId = podState.uniqueId + val podId = uniqueId?.let { Id.fromLong(uniqueId) } + ?: myId.increment() // pod not activated + + val eapSqn = podState.increaseEapAkaSequenceNumber() + val eapAkaExchanger = SessionEstablisher(aapsLogger, mIO, ltk, eapSqn, myId, podId, msgSeq) + val keys = eapAkaExchanger.negotiateSessionKeys() + podState.commitEapAkaSequenceNumber() + + if (BuildConfig.DEBUG) { + aapsLogger.info(LTag.PUMPCOMM, "CK: ${keys.ck.toHex()}") + aapsLogger.info(LTag.PUMPCOMM, "msgSequenceNumber: ${keys.msgSequenceNumber}") + aapsLogger.info(LTag.PUMPCOMM, "Nonce: ${keys.nonce}") + } + sessionKeys = keys + } + + override fun activateNewPod(): Observable = Observable.create { emitter -> + try { + if (podState.ltk != null) { + throw PodAlreadyActivatedException() + } + aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation") + + val podScanner = PodScanner(aapsLogger, bluetoothAdapter) + emitter.onNext(PodEvent.Scanning) + + 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"; + podState.bluetoothAddress = podAddress + emitter.onNext(PodEvent.BluetoothConnecting) + val podDevice = bluetoothAdapter.getRemoteDevice(podAddress) + val bleIO = connect(podDevice) + emitter.onNext(PodEvent.BluetoothConnected) + val mIO = MessageIO(aapsLogger, bleIO) val myId = Id.fromInt(CONTROLLER_ID) val podId = myId.increment() - var msgSeq = 1.toByte() + emitter.onNext(PodEvent.Pairing) + val ltkExchanger = LTKExchanger(aapsLogger, mIO, myId, podId, Id.fromLong(PodScanner.POD_ID_NOT_ACTIVATED)) - if (podState.ltk == null) { - emitter.onNext(PodEvent.Pairing) - val pairResult = ltkExchanger.negotiateLTK() - podState.ltk = pairResult.ltk - podState.uniqueId = podId.toLong() - msgSeq = pairResult.msgSeq - podState.eapAkaSequenceNumber = 1 - if (BuildConfig.DEBUG) { - aapsLogger.info(LTag.PUMPCOMM, "Got LTK: ${pairResult.ltk.toHex()}") - } - } - - val ltk: ByteArray = podState.ltk!! - - emitter.onNext(PodEvent.EstablishingSession) - val eapSqn = podState.increaseEapAkaSequenceNumber() - val eapAkaExchanger = SessionEstablisher(aapsLogger, mIO, ltk, eapSqn, myId, podId, msgSeq) - val keys = eapAkaExchanger.negotiateSessionKeys() - podState.commitEapAkaSequenceNumber() - + val pairResult = ltkExchanger.negotiateLTK() + podState.ltk = pairResult.ltk + podState.eapAkaSequenceNumber = 1 + emitter.onNext(PodEvent.Paired(podId)) + podState.uniqueId = podId.toLong() + val msgSeq = pairResult.msgSeq if (BuildConfig.DEBUG) { - aapsLogger.info(LTag.PUMPCOMM, "CK: ${keys.ck.toHex()}") - aapsLogger.info(LTag.PUMPCOMM, "msgSequenceNumber: ${keys.msgSequenceNumber}") - aapsLogger.info(LTag.PUMPCOMM, "Nonce: ${keys.nonce}") + aapsLogger.info(LTag.PUMPCOMM, "Got LTK: ${pairResult.ltk.toHex()}") } - sessionKeys = keys - msgIO = mIO - - emitter.onNext(PodEvent.Connected(podId.toLong())) + emitter.onNext(PodEvent.EstablishingSession) + establishSession(msgSeq) + emitter.onNext(PodEvent.Paired(podId)) emitter.onComplete() } catch (ex: Exception) { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/PodAlreadyActivatedException.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/PodAlreadyActivatedException.kt new file mode 100644 index 0000000000..1564f85b85 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/PodAlreadyActivatedException.kt @@ -0,0 +1,4 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions + +class PodAlreadyActivatedException: Exception("The pod is already activated") { +} \ 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 9e6e994aa4..8831ba3d81 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 @@ -123,6 +123,6 @@ class BleIO( companion object { - private const val DEFAULT_IO_TIMEOUT_MS = 10000 + private const val DEFAULT_IO_TIMEOUT_MS = 60000 } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt index e45c9a322a..720fbce383 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt @@ -67,7 +67,7 @@ class Session( payload = ByteArray(0), eqos = 0, ack = true, - ackNumber = (response.sequenceNumber.toInt()+1).toByte() + ackNumber = response.sequenceNumber.inc() ) return enDecrypt.encrypt((msg)) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt index b0429dd1d5..54720e1104 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt @@ -1,19 +1,20 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response sealed class PodEvent { /* BT connection events */ - class AlreadyConnected(val bluetoothAddress: String, val uniqueId: Long) : PodEvent() + class AlreadyConnected(val bluetoothAddress: String) : PodEvent() object Scanning : PodEvent() object BluetoothConnecting : PodEvent() - class BluetoothConnected(val address: String) : PodEvent() + object BluetoothConnected : PodEvent() object Pairing : PodEvent() - object Paired : PodEvent() + class Paired(val uniqueId: Id) : PodEvent() object EstablishingSession : PodEvent() - class Connected(val uniqueId: Long) : PodEvent() + object Connected : PodEvent() /* Message exchange events */ class CommandSending(val command: Command) : PodEvent()