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()
This commit is contained in:
parent
034cbef215
commit
8154e16c94
7 changed files with 99 additions and 61 deletions
|
@ -50,7 +50,12 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
private val observeConnectToPod: Observable<PodEvent>
|
private val observeConnectToPod: Observable<PodEvent>
|
||||||
get() = Observable.defer {
|
get() = Observable.defer {
|
||||||
bleManager.connect()
|
bleManager.connect()
|
||||||
|
} // TODO are these reasonable values?
|
||||||
|
|
||||||
|
|
||||||
|
private val observeScanAndActivateNewPod: Observable<PodEvent>
|
||||||
|
get() = Observable.defer {
|
||||||
|
bleManager.activateNewPod()
|
||||||
} // TODO are these reasonable values?
|
} // TODO are these reasonable values?
|
||||||
|
|
||||||
private fun observeSendProgramBolusCommand(
|
private fun observeSendProgramBolusCommand(
|
||||||
|
@ -172,7 +177,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
override fun activatePodPart1(lowReservoirAlertTrigger: AlertTrigger.ReservoirVolumeTrigger?): Observable<PodEvent> {
|
override fun activatePodPart1(lowReservoirAlertTrigger: AlertTrigger.ReservoirVolumeTrigger?): Observable<PodEvent> {
|
||||||
return Observable.concat(
|
return Observable.concat(
|
||||||
observePodReadyForActivationPart1,
|
observePodReadyForActivationPart1,
|
||||||
observeConnectToPod,
|
observeScanAndActivateNewPod,
|
||||||
observeActivationPart1Commands(lowReservoirAlertTrigger)
|
observeActivationPart1Commands(lowReservoirAlertTrigger)
|
||||||
).doOnComplete(ActivationProgressUpdater(ActivationProgress.PHASE_1_COMPLETED))
|
).doOnComplete(ActivationProgressUpdater(ActivationProgress.PHASE_1_COMPLETED))
|
||||||
// TODO these would be common for any observable returned in a public function in this class
|
// 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) {
|
when (event) {
|
||||||
is PodEvent.AlreadyConnected -> {
|
is PodEvent.AlreadyConnected -> {
|
||||||
podStateManager.bluetoothAddress = event.bluetoothAddress
|
podStateManager.bluetoothAddress = event.bluetoothAddress
|
||||||
podStateManager.uniqueId = event.uniqueId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PodEvent.BluetoothConnected -> {
|
is PodEvent.BluetoothConnected -> {
|
||||||
podStateManager.bluetoothAddress = event.address
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PodEvent.Connected -> {
|
is PodEvent.Connected -> {
|
||||||
podStateManager.uniqueId = event.uniqueId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PodEvent.CommandSent -> {
|
is PodEvent.CommandSent -> {
|
||||||
|
@ -427,7 +429,11 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
handleResponse(event.response)
|
handleResponse(event.response)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
is PodEvent.Paired -> {
|
||||||
|
podStateManager.uniqueId = event.uniqueId.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,5 +13,7 @@ interface OmnipodDashBleManager {
|
||||||
|
|
||||||
fun connect(): Observable<PodEvent>
|
fun connect(): Observable<PodEvent>
|
||||||
|
|
||||||
|
fun activateNewPod(): Observable<PodEvent>
|
||||||
|
|
||||||
fun disconnect()
|
fun disconnect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
DescriptorNotFoundException::class,
|
DescriptorNotFoundException::class,
|
||||||
CouldNotConfirmDescriptorWriteException::class
|
CouldNotConfirmDescriptorWriteException::class
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun connect(podDevice: BluetoothDevice): BleIO {
|
private fun connect(podDevice: BluetoothDevice): BleIO {
|
||||||
val incomingPackets: Map<CharacteristicType, BlockingQueue<ByteArray>> =
|
val incomingPackets: Map<CharacteristicType, BlockingQueue<ByteArray>> =
|
||||||
mapOf(
|
mapOf(
|
||||||
|
@ -90,7 +91,6 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
val keys = sessionKeys
|
val keys = sessionKeys
|
||||||
val mIO = msgIO
|
val mIO = msgIO
|
||||||
if (keys == null || mIO == null) {
|
if (keys == null || mIO == null) {
|
||||||
// TODO handle reconnects
|
|
||||||
throw Exception("Not connected")
|
throw Exception("Not connected")
|
||||||
}
|
}
|
||||||
emitter.onNext(PodEvent.CommandSending(cmd))
|
emitter.onNext(PodEvent.CommandSending(cmd))
|
||||||
|
@ -142,75 +142,100 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun connect(): Observable<PodEvent> = Observable.create { emitter ->
|
override fun connect(): Observable<PodEvent> = Observable.create { emitter ->
|
||||||
// TODO: when we are already connected,
|
|
||||||
// emit PodEvent.AlreadyConnected, complete the observable and return from this method
|
|
||||||
try {
|
try {
|
||||||
if (podState.bluetoothAddress == null) {
|
|
||||||
aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation")
|
|
||||||
|
|
||||||
val podScanner = PodScanner(aapsLogger, bluetoothAdapter)
|
val podAddress = podState.bluetoothAddress ?: throw FailedToConnectException("Missing bluetoothAddress, activate the pod first")
|
||||||
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")
|
|
||||||
// check if already connected
|
// check if already connected
|
||||||
val podDevice = bluetoothAdapter.getRemoteDevice(podAddress)
|
val podDevice = bluetoothAdapter.getRemoteDevice(podAddress)
|
||||||
val connectionState = bluetoothManager.getConnectionState(podDevice, BluetoothProfile.GATT)
|
val connectionState = bluetoothManager.getConnectionState(podDevice, BluetoothProfile.GATT)
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "GATT connection state: $connectionState")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "GATT connection state: $connectionState")
|
||||||
|
|
||||||
emitter.onNext(PodEvent.BluetoothConnected(podAddress))
|
|
||||||
if (connectionState == BluetoothProfile.STATE_CONNECTED) {
|
if (connectionState == BluetoothProfile.STATE_CONNECTED) {
|
||||||
podState.uniqueId ?: throw FailedToConnectException("Already connection and uniqueId is missing")
|
emitter.onNext(PodEvent.AlreadyConnected(podAddress))
|
||||||
emitter.onNext(PodEvent.AlreadyConnected(podAddress, podState.uniqueId ?: 0))
|
|
||||||
emitter.onComplete()
|
emitter.onComplete()
|
||||||
return@create
|
return@create
|
||||||
}
|
}
|
||||||
|
emitter.onNext(PodEvent.BluetoothConnecting)
|
||||||
if (msgIO != null) {
|
if (msgIO != null) {
|
||||||
disconnect()
|
disconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
val bleIO = connect(podDevice)
|
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<PodEvent> = 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 mIO = MessageIO(aapsLogger, bleIO)
|
||||||
val myId = Id.fromInt(CONTROLLER_ID)
|
val myId = Id.fromInt(CONTROLLER_ID)
|
||||||
val podId = myId.increment()
|
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))
|
val ltkExchanger = LTKExchanger(aapsLogger, mIO, myId, podId, Id.fromLong(PodScanner.POD_ID_NOT_ACTIVATED))
|
||||||
if (podState.ltk == null) {
|
val pairResult = ltkExchanger.negotiateLTK()
|
||||||
emitter.onNext(PodEvent.Pairing)
|
podState.ltk = pairResult.ltk
|
||||||
val pairResult = ltkExchanger.negotiateLTK()
|
podState.eapAkaSequenceNumber = 1
|
||||||
podState.ltk = pairResult.ltk
|
emitter.onNext(PodEvent.Paired(podId))
|
||||||
podState.uniqueId = podId.toLong()
|
podState.uniqueId = podId.toLong()
|
||||||
msgSeq = pairResult.msgSeq
|
val 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()
|
|
||||||
|
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
aapsLogger.info(LTag.PUMPCOMM, "CK: ${keys.ck.toHex()}")
|
aapsLogger.info(LTag.PUMPCOMM, "Got LTK: ${pairResult.ltk.toHex()}")
|
||||||
aapsLogger.info(LTag.PUMPCOMM, "msgSequenceNumber: ${keys.msgSequenceNumber}")
|
|
||||||
aapsLogger.info(LTag.PUMPCOMM, "Nonce: ${keys.nonce}")
|
|
||||||
}
|
}
|
||||||
sessionKeys = keys
|
emitter.onNext(PodEvent.EstablishingSession)
|
||||||
msgIO = mIO
|
establishSession(msgSeq)
|
||||||
|
emitter.onNext(PodEvent.Paired(podId))
|
||||||
emitter.onNext(PodEvent.Connected(podId.toLong()))
|
|
||||||
|
|
||||||
emitter.onComplete()
|
emitter.onComplete()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||||
|
|
||||||
|
class PodAlreadyActivatedException: Exception("The pod is already activated") {
|
||||||
|
}
|
|
@ -123,6 +123,6 @@ class BleIO(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val DEFAULT_IO_TIMEOUT_MS = 10000
|
private const val DEFAULT_IO_TIMEOUT_MS = 60000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ class Session(
|
||||||
payload = ByteArray(0),
|
payload = ByteArray(0),
|
||||||
eqos = 0,
|
eqos = 0,
|
||||||
ack = true,
|
ack = true,
|
||||||
ackNumber = (response.sequenceNumber.toInt()+1).toByte()
|
ackNumber = response.sequenceNumber.inc()
|
||||||
)
|
)
|
||||||
return enDecrypt.encrypt((msg))
|
return enDecrypt.encrypt((msg))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event
|
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.command.base.Command
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response
|
||||||
|
|
||||||
sealed class PodEvent {
|
sealed class PodEvent {
|
||||||
|
|
||||||
/* BT connection events */
|
/* BT connection events */
|
||||||
class AlreadyConnected(val bluetoothAddress: String, val uniqueId: Long) : PodEvent()
|
class AlreadyConnected(val bluetoothAddress: String) : PodEvent()
|
||||||
object Scanning : PodEvent()
|
object Scanning : PodEvent()
|
||||||
object BluetoothConnecting : PodEvent()
|
object BluetoothConnecting : PodEvent()
|
||||||
class BluetoothConnected(val address: String) : PodEvent()
|
object BluetoothConnected : PodEvent()
|
||||||
object Pairing : PodEvent()
|
object Pairing : PodEvent()
|
||||||
object Paired : PodEvent()
|
class Paired(val uniqueId: Id) : PodEvent()
|
||||||
object EstablishingSession : PodEvent()
|
object EstablishingSession : PodEvent()
|
||||||
class Connected(val uniqueId: Long) : PodEvent()
|
object Connected : PodEvent()
|
||||||
|
|
||||||
/* Message exchange events */
|
/* Message exchange events */
|
||||||
class CommandSending(val command: Command) : PodEvent()
|
class CommandSending(val command: Command) : PodEvent()
|
||||||
|
|
Loading…
Add table
Reference in a new issue