From fe9c5d00a771025ab1c1b13a0c5db91b3308fc90 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Wed, 31 Mar 2021 11:18:58 +0200 Subject: [PATCH] WIP on implementing OmnipodDashPumpPlugin + some autoformatting --- ...eAlerts.java => CommandSilenceAlerts.java} | 2 +- .../omnipod/dash/OmnipodDashPumpPlugin.kt | 384 ++++++++++++++++-- .../omnipod/dash/driver/OmnipodDashManager.kt | 4 +- .../dash/driver/OmnipodDashManagerImpl.kt | 6 +- .../pump/omnipod/dash/driver/comm/Id.kt | 4 +- .../dash/driver/comm/pair/KeyExchange.kt | 1 + .../driver/comm/session/EapAkaAttribute.kt | 26 +- .../driver/comm/session/SessionEstablisher.kt | 6 +- .../pod/command/ProgramInsulinCommand.kt | 2 +- .../pod/state/OmnipodDashPodStateManager.kt | 2 +- .../state/OmnipodDashPodStateManagerImpl.kt | 26 +- .../dash/ui/DashPodManagementActivity.kt | 30 +- .../dash/ui/OmnipodDashOverviewFragment.kt | 6 +- .../action/DashDeactivatePodViewModel.kt | 27 +- .../layout/omnipod_dash_pod_management.xml | 6 +- .../omnipod/eros/OmnipodErosPumpPlugin.java | 10 +- .../eros/ui/OmnipodErosOverviewFragment.kt | 8 +- .../layout/omnipod_eros_pod_management.xml | 5 +- 18 files changed, 469 insertions(+), 86 deletions(-) rename omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/{CommandAcknowledgeAlerts.java => CommandSilenceAlerts.java} (80%) diff --git a/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandAcknowledgeAlerts.java b/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandSilenceAlerts.java similarity index 80% rename from omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandAcknowledgeAlerts.java rename to omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandSilenceAlerts.java index ea8aa4fba3..b0089d949f 100644 --- a/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandAcknowledgeAlerts.java +++ b/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandSilenceAlerts.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull; import info.nightscout.androidaps.queue.commands.CustomCommand; -public final class CommandAcknowledgeAlerts implements CustomCommand { +public final class CommandSilenceAlerts implements CustomCommand { @NotNull @Override public String getStatusDescription() { return "ACKNOWLEDGE ALERTS"; } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.kt index 48e42bf723..b71e81463d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.kt @@ -11,13 +11,23 @@ import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment +import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram import info.nightscout.androidaps.queue.commands.CustomCommand import info.nightscout.androidaps.utils.TimeChangeType import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.Single +import io.reactivex.rxkotlin.blockingSubscribeBy +import io.reactivex.rxkotlin.subscribeBy import org.json.JSONObject +import java.util.* import javax.inject.Inject import javax.inject.Singleton @@ -25,6 +35,8 @@ import javax.inject.Singleton class OmnipodDashPumpPlugin @Inject constructor( private val omnipodManager: OmnipodDashManager, private val podStateManager: OmnipodDashPodStateManager, + private val sp: SP, + private val profileFunction: ProfileFunction, injector: HasAndroidInjector, aapsLogger: AAPSLogger, resourceHelper: ResourceHelper, @@ -51,19 +63,17 @@ class OmnipodDashPumpPlugin @Inject constructor( } override fun isSuspended(): Boolean { - // TODO - return false + return podStateManager.isSuspended } override fun isBusy(): Boolean { // prevents the queue from executing commands - // TODO - return true + return podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED) } override fun isConnected(): Boolean { // TODO - return false + return true } override fun isConnecting(): Boolean { @@ -93,40 +103,136 @@ class OmnipodDashPumpPlugin @Inject constructor( } override fun getPumpStatus(reason: String) { - // TODO + // TODO history + + omnipodManager.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE).blockingSubscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in getPumpStatus: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", throwable) + }, + onComplete = { + aapsLogger.debug("getPumpStatus completed") + } + ) } override fun setNewBasalProfile(profile: Profile): PumpEnactResult { - // TODO - return PumpEnactResult(injector).success(true).enacted(true) + // TODO history + + return Single.create { source -> + omnipodManager.setBasalProgram(mapProfileToBasalProgram(profile)).subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in setNewBasalProfile: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in setNewBasalProfile", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("setNewBasalProfile completed") + source.onSuccess(PumpEnactResult(injector).success(true).enacted(true)) + } + ) + }.blockingGet() } override fun isThisProfileSet(profile: Profile): Boolean { - // TODO - return true + if (podStateManager.basalProgram == null) { + // We don't have an active Pod. Return true here because the next Pod will use the currently active profile + return true + } + return podStateManager.basalProgram!! == mapProfileToBasalProgram(profile) } override fun lastDataTime(): Long { - // TODO - return System.currentTimeMillis() + return podStateManager.lastConnection } override val baseBasalRate: Double - get() = 0.0 // TODO + get() { + if (podStateManager.basalProgram == null) { + return 0.0 + } + return podStateManager.basalProgram!!.rateAt(Date()) + } override val reservoirLevel: Double - get() = 0.0 // TODO + get() { + if (podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)) { + return 0.0 + } + + // Omnipod only reports reservoir level when there's < 1023 pulses left + return podStateManager.pulsesRemaining?.let { + it * 0.05 + } ?: 75.0 + } override val batteryLevel: Int + // Omnipod Dash doesn't report it's battery level. We return 0 here and hide related fields in the UI get() = 0 override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { - // TODO - return PumpEnactResult(injector).success(false).enacted(false).comment("TODO") + // TODO history + // TODO update Treatments (?) + // TODO bolus progress + // TODO report actual delivered amount after Pod Alarm and bolus cancellation + + return Single.create { source -> + val bolusBeeps = sp.getBoolean(R.string.key_omnipod_common_bolus_beeps_enabled, false) + + omnipodManager.bolus( + detailedBolusInfo.insulin, + bolusBeeps, + bolusBeeps + ).subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in deliverTreatment: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in deliverTreatment", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("deliverTreatment completed") + source.onSuccess( + PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(detailedBolusInfo.insulin) + .carbsDelivered(detailedBolusInfo.carbs) + ) + } + ) + }.blockingGet() } override fun stopBolusDelivering() { - // TODO + // TODO history + // TODO update Treatments (?) + + omnipodManager.stopBolus().blockingSubscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in stopBolusDelivering: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in stopBolusDelivering", throwable) + }, + onComplete = { + aapsLogger.debug("stopBolusDelivering completed") + } + ) } override fun setTempBasalAbsolute( @@ -135,8 +241,33 @@ class OmnipodDashPumpPlugin @Inject constructor( profile: Profile, enforceNew: Boolean ): PumpEnactResult { - // TODO - return PumpEnactResult(injector).success(false).enacted(false).comment("TODO") + // TODO history + // TODO update Treatments + + return Single.create { source -> + omnipodManager.setTempBasal( + absoluteRate, + durationInMinutes.toShort() + ).subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in setTempBasalAbsolute: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in setTempBasalAbsolute", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("setTempBasalAbsolute completed") + source.onSuccess( + PumpEnactResult(injector).success(true).enacted(true).absolute(absoluteRate) + .duration(durationInMinutes) + ) + } + ) + }.blockingGet() } override fun setTempBasalPercent( @@ -157,8 +288,29 @@ class OmnipodDashPumpPlugin @Inject constructor( } override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { - // TODO - return PumpEnactResult(injector).success(false).enacted(false).comment("TODO") + // TODO history + // TODO update Treatments + + return Single.create { source -> + omnipodManager.stopTempBasal().subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in cancelTempBasal: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in cancelTempBasal", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("cancelTempBasal completed") + source.onSuccess( + PumpEnactResult(injector).success(true).enacted(true) + ) + } + ) + }.blockingGet() } override fun cancelExtendedBolus(): PumpEnactResult { @@ -183,8 +335,11 @@ class OmnipodDashPumpPlugin @Inject constructor( } override fun serialNumber(): String { - // TODO - return "TODO" + return if (podStateManager.uniqueId == null) { + "n/a" // TODO i18n + } else { + podStateManager.uniqueId.toString() + } } override fun shortStatus(veryShort: Boolean): String { @@ -214,11 +369,190 @@ class OmnipodDashPumpPlugin @Inject constructor( } override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? { + if (customCommand is CommandSilenceAlerts) { + return silenceAlerts() + } + if (customCommand is CommandSuspendDelivery) { + return suspendDelivery() + } + if (customCommand is CommandResumeDelivery) { + return resumeDelivery() + } + if (customCommand is CommandDeactivatePod) { + return deactivatePod() + } + if (customCommand is CommandHandleTimeChange) { + return handleTimeChange() + } + if (customCommand is CommandUpdateAlertConfiguration) { + return updateAlertConfiguration() + } + if (customCommand is CommandPlayTestBeep) { + return playTestBeep() + } + + aapsLogger.warn(LTag.PUMP, "Unsupported custom command: " + customCommand.javaClass.name) + + return PumpEnactResult(injector).success(false).enacted(false).comment( + resourceHelper.gs( + R.string.omnipod_common_error_unsupported_custom_command, + customCommand.javaClass.name + ) + ) + } + + private fun silenceAlerts(): PumpEnactResult { + // TODO history + // TODO filter alert types + + return podStateManager.activeAlerts?.let { + Single.create { source -> + omnipodManager.silenceAlerts(it).subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in silenceAlerts: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in silenceAlerts", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("silenceAlerts completed") + source.onSuccess(PumpEnactResult(injector).success(true)) + } + ) + }.blockingGet() + } ?: PumpEnactResult(injector).success(false).enacted(false).comment("No active alerts") // TODO i18n + } + + private fun suspendDelivery(): PumpEnactResult { + // TODO history + + return Single.create { source -> + omnipodManager.suspendDelivery().subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in suspendDelivery: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in suspendDelivery", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("suspendDelivery completed") + source.onSuccess(PumpEnactResult(injector).success(true)) + } + ) + }.blockingGet() + } + + private fun resumeDelivery(): PumpEnactResult { + // TODO history + + return profileFunction.getProfile()?.let { + + Single.create { source -> + omnipodManager.setBasalProgram(mapProfileToBasalProgram(it)).subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in resumeDelivery: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in resumeDelivery", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("resumeDelivery completed") + source.onSuccess(PumpEnactResult(injector).success(true)) + } + ) + }.blockingGet() + } ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n + } + + private fun deactivatePod(): PumpEnactResult { + // TODO history + + return Single.create { source -> + omnipodManager.deactivatePod().subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in deactivatePod: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in deactivatePod", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("deactivatePod completed") + source.onSuccess(PumpEnactResult(injector).success(true)) + } + ) + }.blockingGet() + } + + private fun handleTimeChange(): PumpEnactResult { // TODO - return null + return PumpEnactResult(injector).success(false).enacted(false).comment("NOT IMPLEMENTED") + } + + private fun updateAlertConfiguration(): PumpEnactResult { + // TODO + return PumpEnactResult(injector).success(false).enacted(false).comment("NOT IMPLEMENTED") + } + + private fun playTestBeep(): PumpEnactResult { + // TODO history + + return Single.create { source -> + omnipodManager.playBeep(BeepType.LONG_SINGLE_BEEP).subscribeBy( + onNext = { podEvent -> + aapsLogger.debug( + LTag.PUMP, + "Received PodEvent in playTestBeep: $podEvent" + ) + }, + onError = { throwable -> + aapsLogger.error(LTag.PUMP, "Error in playTestBeep", throwable) + source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message)) + }, + onComplete = { + aapsLogger.debug("playTestBeep completed") + source.onSuccess( + PumpEnactResult(injector).success(true).enacted(true) + ) + } + ) + }.blockingGet() } override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) { - // TODO + val eventHandlingEnabled = sp.getBoolean(R.string.key_omnipod_common_time_change_event_enabled, false) + + aapsLogger.info( + LTag.PUMP, + "Time, Date and/or TimeZone changed. [timeChangeType=" + timeChangeType.name + ", eventHandlingEnabled=" + eventHandlingEnabled + "]" + ) + + + if (timeChangeType == TimeChangeType.TimeChanged) { + aapsLogger.info(LTag.PUMP, "Ignoring time change because it is not a DST or TZ change") + return + } else if (!podStateManager.isPodRunning) { + aapsLogger.info(LTag.PUMP, "Ignoring time change because no Pod is active") + return + } + + aapsLogger.info(LTag.PUMP, "Handling time change") + + commandQueue.customCommand(CommandHandleTimeChange(false), null) } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManager.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManager.kt index 5db4fad6c3..2b9333bdab 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManager.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManager.kt @@ -26,11 +26,11 @@ interface OmnipodDashManager { fun setTempBasal(rate: Double, durationInMinutes: Short): Observable - fun cancelTempBasal(): Observable + fun stopTempBasal(): Observable fun bolus(units: Double, confirmationBeeps: Boolean, completionBeeps: Boolean): Observable - fun cancelBolus(): Observable + fun stopBolus(): Observable fun playBeep(beepType: BeepType): Observable 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 8c76ed2cc0..450fc644d5 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 @@ -170,6 +170,8 @@ class OmnipodDashManagerImpl @Inject constructor( .build(), DefaultStatusResponse::class ) + }.doOnComplete { + podStateManager.basalProgram = basalProgram } } @@ -483,7 +485,7 @@ class OmnipodDashManagerImpl @Inject constructor( .subscribeOn(aapsSchedulers.io) } - override fun cancelTempBasal(): Observable { + override fun stopTempBasal(): Observable { return Observable.concat( observePodRunning, observeConnectToPod, @@ -512,7 +514,7 @@ class OmnipodDashManagerImpl @Inject constructor( .subscribeOn(aapsSchedulers.io) } - override fun cancelBolus(): Observable { + override fun stopBolus(): Observable { return Observable.concat( observePodRunning, observeConnectToPod, diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt index 11c32853e7..d71f0ef688 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt @@ -46,11 +46,13 @@ data class Id(val address: ByteArray) { companion object { - private const val PERIPHERAL_NODE_INDEX = 1 // TODO: understand the meaning of this value. It comes from preferences + private const val PERIPHERAL_NODE_INDEX = + 1 // TODO: understand the meaning of this value. It comes from preferences fun fromInt(v: Int): Id { return Id(ByteBuffer.allocate(4).putInt(v).array()) } + fun fromLong(v: Long): Id { return Id(ByteBuffer.allocate(8).putLong(v).array().copyOfRange(4, 8)) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchange.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchange.kt index 90130a29f0..68c4b1f285 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchange.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchange.kt @@ -16,6 +16,7 @@ class KeyExchange( var pdmPrivate: ByteArray = X25519.generatePrivateKey(), val pdmNonce: ByteArray = ByteArray(NONCE_SIZE) ) { + val pdmPublic = X25519.publicFromPrivate(pdmPrivate) var podPublic = ByteArray(PUBLIC_KEY_SIZE) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt index 701c96d516..d02bb1a835 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt @@ -50,7 +50,14 @@ sealed class EapAkaAttribute { EapAkaAttributeType.AT_RAND -> ret.add(EapAkaAttributeRand.parse(tail.copyOfRange(2, EapAkaAttributeRand.SIZE))) EapAkaAttributeType.AT_CLIENT_ERROR_CODE -> - ret.add(EapAkaAttributeClientErrorCode.parse(tail.copyOfRange(2, EapAkaAttributeClientErrorCode.SIZE))) + ret.add( + EapAkaAttributeClientErrorCode.parse( + tail.copyOfRange( + 2, + EapAkaAttributeClientErrorCode.SIZE + ) + ) + ) } tail = tail.copyOfRange(size, tail.size) } @@ -70,12 +77,14 @@ data class EapAkaAttributeRand(val payload: ByteArray) : EapAkaAttribute() { } companion object { + fun parse(payload: ByteArray): EapAkaAttribute { if (payload.size < 2 + 16) { throw MessageIOException("Could not parse RAND attribute: ${payload.toHex()}") } return EapAkaAttributeRand(payload.copyOfRange(2, 2 + 16)) } + const val SIZE = 20 // type, size, 2 reserved bytes, payload=16 } } @@ -110,7 +119,12 @@ data class EapAkaAttributeRes(val payload: ByteArray) : EapAkaAttribute() { } override fun toByteArray(): ByteArray { - return byteArrayOf(EapAkaAttributeType.AT_RES.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, PAYLOAD_SIZE_BITS) + payload + return byteArrayOf( + EapAkaAttributeType.AT_RES.type, + (SIZE / SIZE_MULTIPLIER).toByte(), + 0, + PAYLOAD_SIZE_BITS + ) + payload } companion object { @@ -145,6 +159,7 @@ data class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute() { } return EapAkaAttributeCustomIV(payload.copyOfRange(2, 2 + 4)) } + const val SIZE = 8 // type, size, 2 reserved bytes, payload=4 } } @@ -156,7 +171,12 @@ data class EapAkaAttributeClientErrorCode(val payload: ByteArray) : EapAkaAttrib } override fun toByteArray(): ByteArray { - return byteArrayOf(EapAkaAttributeType.AT_CLIENT_ERROR_CODE.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload + return byteArrayOf( + EapAkaAttributeType.AT_CLIENT_ERROR_CODE.type, + (SIZE / SIZE_MULTIPLIER).toByte(), + 0, + 0 + ) + payload } companion object { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt index 41c7e9855b..828246365c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt @@ -86,7 +86,11 @@ class SessionEstablisher( aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg") if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) { // TODO: special exception for this - throw SessionEstablishmentException("Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${eapMsg.attributes[0].toByteArray().toHex()}") + throw SessionEstablishmentException( + "Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${ + eapMsg.attributes[0].toByteArray().toHex() + }" + ) } throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}") } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.kt index 930f376ec7..d6f3a4465d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.kt @@ -13,7 +13,7 @@ class ProgramInsulinCommand internal constructor( multiCommandFlag: Boolean, nonce: Int, insulinProgramElements: - List, + List, private val checksum: Short, private val byte9: Byte, private val byte10And11: Short, diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt index 51cab91974..6f2a66300d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt @@ -47,7 +47,7 @@ interface OmnipodDashPodStateManager { val tempBasal: TempBasal? val tempBasalActive: Boolean - val basalProgram: BasalProgram? + var basalProgram: BasalProgram? fun increaseMessageSequenceNumber() fun increaseEapAkaSequenceNumber(): ByteArray diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt index b55719a341..94aaca41cc 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt @@ -35,8 +35,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( override var activationProgress: ActivationProgress get() = podState.activationProgress - set(value) { - podState.activationProgress = value + set(activationProgress) { + podState.activationProgress = activationProgress store() } @@ -55,8 +55,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( override var lastConnection: Long get() = podState.lastConnection - set(value) { - podState.lastConnection = value + set(lastConnection) { + podState.lastConnection = lastConnection store() } @@ -145,8 +145,12 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( override val tempBasalActive: Boolean get() = tempBasal != null && tempBasal!!.startTime + tempBasal!!.durationInMinutes * 60 * 1000 > System.currentTimeMillis() - override val basalProgram: BasalProgram? + override var basalProgram: BasalProgram? get() = podState.basalProgram + set(basalProgram) { + podState.basalProgram = basalProgram + store() + } override fun increaseMessageSequenceNumber() { podState.messageSequenceNumber = ((podState.messageSequenceNumber.toInt() + 1) and 0x0f).toShort() @@ -155,15 +159,15 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( override var eapAkaSequenceNumber: Long get() = podState.eapAkaSequenceNumber - set(value) { - podState.eapAkaSequenceNumber = value + set(eapAkaSequenceNumber) { + podState.eapAkaSequenceNumber = eapAkaSequenceNumber store() } override var ltk: ByteArray? get() = podState.ltk - set(value) { - podState.ltk = value + set(ltk) { + podState.ltk = ltk store() } @@ -183,7 +187,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( podState.deliveryStatus = response.deliveryStatus podState.podStatus = response.podStatus podState.pulsesDelivered = response.totalPulsesDelivered - podState.pulsesRemaining = response.reservoirPulsesRemaining + if (response.reservoirPulsesRemaining < 1023) { + podState.pulsesRemaining = response.reservoirPulsesRemaining + } podState.sequenceNumberOfLastProgrammingCommand = response.sequenceNumberOfLastProgrammingCommand podState.minutesSinceActivation = response.minutesSinceActivation podState.activeAlerts = response.activeAlerts diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt index 4e0df13403..6dc63d5c46 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt @@ -20,6 +20,7 @@ import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.events.EventQueueChanged import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.alertDialogs.OKDialog +import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign @@ -73,7 +74,6 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() { } binding.buttonPlayTestBeep.setOnClickListener { - // TODO binding.buttonPlayTestBeep.isEnabled = false binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_playing_test_beep) @@ -114,7 +114,33 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() { } private fun refreshButtons() { - // TODO update button state from Pod state + // Only show the discard button to reset a cached unique ID before the unique ID has actually been set + // Otherwise, users should use the Deactivate Pod Wizard. In case proper deactivation fails, + // they will get an option to discard the Pod there + val discardButtonEnabled = + podStateManager.uniqueId != null && podStateManager.activationProgress.isBefore(ActivationProgress.SET_UNIQUE_ID) + binding.buttonDiscardPod.visibility = discardButtonEnabled.toVisibility() + + binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED) + binding.buttonDeactivatePod.isEnabled = + podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) + + if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)) { + if (commandQueue.isCustomCommandInQueue(CommandPlayTestBeep::class.java)) { + binding.buttonPlayTestBeep.isEnabled = false + binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_playing_test_beep) + } else { + binding.buttonPlayTestBeep.isEnabled = true + binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_play_test_beep) + } + } else { + binding.buttonPlayTestBeep.isEnabled = false + binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_play_test_beep) + } + + if (discardButtonEnabled) { + binding.buttonDiscardPod.isEnabled = true + } } private fun displayErrorDialog(title: String, message: String, @Suppress("SameParameterValue") withSound: Boolean) { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt index b2351d4f75..a235f8effb 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt @@ -18,7 +18,7 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewButtonsBinding import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewPodInfoBinding -import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandAcknowledgeAlerts +import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery @@ -130,7 +130,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() { buttonBinding.buttonSilenceAlerts.setOnClickListener { disablePodActionButtons() commandQueue.customCommand( - CommandAcknowledgeAlerts(), + CommandSilenceAlerts(), DisplayResultDialogCallback( resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts), false @@ -486,7 +486,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() { private fun updateSilenceAlertsButton() { if (isAutomaticallySilenceAlertsEnabled() && podStateManager.isPodRunning && (podStateManager.activeAlerts!!.size > 0 || commandQueue.isCustomCommandInQueue( - CommandAcknowledgeAlerts::class.java + CommandSilenceAlerts::class.java ))) { buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE buttonBinding.buttonSilenceAlerts.isEnabled = isQueueEmpty() diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt index f5f5475d0e..b0ffeadc77 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt @@ -3,40 +3,29 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.deactivat import androidx.annotation.StringRes import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.logging.AAPSLogger -import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.omnipod.common.R +import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandDeactivatePod import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.deactivation.viewmodel.action.DeactivatePodViewModel -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager +import info.nightscout.androidaps.queue.Callback import io.reactivex.Single -import io.reactivex.rxkotlin.subscribeBy import javax.inject.Inject class DashDeactivatePodViewModel @Inject constructor( - private val omnipodManager: OmnipodDashManager, private val podStateManager: OmnipodDashPodStateManager, + private val commandQueueProvider: CommandQueueProvider, injector: HasAndroidInjector, logger: AAPSLogger ) : DeactivatePodViewModel(injector, logger) { override fun doExecuteAction(): Single = Single.create { source -> - omnipodManager.deactivatePod().subscribeBy( - onNext = { podEvent -> - logger.debug( - LTag.PUMP, - "Received PodEvent in Pod deactivation: $podEvent" - ) - }, - onError = { throwable -> - logger.error(LTag.PUMP, "Error in Pod deactivation", throwable) - source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message)) - }, - onComplete = { - logger.debug("Pod deactivation completed") - source.onSuccess(PumpEnactResult(injector).success(true)) + commandQueueProvider.customCommand(CommandDeactivatePod(), object : Callback() { + override fun run() { + source.onSuccess(result) } - ) + }) } override fun discardPod() { diff --git a/omnipod-dash/src/main/res/layout/omnipod_dash_pod_management.xml b/omnipod-dash/src/main/res/layout/omnipod_dash_pod_management.xml index 461781eabe..4ea9533d45 100644 --- a/omnipod-dash/src/main/res/layout/omnipod_dash_pod_management.xml +++ b/omnipod-dash/src/main/res/layout/omnipod_dash_pod_management.xml @@ -14,7 +14,6 @@ android:orientation="vertical"> - - 0 && !getCommandQueue().isCustomCommandInQueue(CommandAcknowledgeAlerts.class)) { + podStateManager.getActiveAlerts().size() > 0 && !getCommandQueue().isCustomCommandInQueue(CommandSilenceAlerts.class)) { queueAcknowledgeAlertsCommand(); } } else { @@ -410,7 +410,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa rxBus.send(new EventNewNotification(notification)); nsUpload.uploadError(notificationText); - if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && !getCommandQueue().isCustomCommandInQueue(CommandAcknowledgeAlerts.class)) { + if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && !getCommandQueue().isCustomCommandInQueue(CommandSilenceAlerts.class)) { queueAcknowledgeAlertsCommand(); } } @@ -437,7 +437,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa } private void queueAcknowledgeAlertsCommand() { - getCommandQueue().customCommand(new CommandAcknowledgeAlerts(), new Callback() { + getCommandQueue().customCommand(new CommandSilenceAlerts(), new Callback() { @Override public void run() { if (result != null) { aapsLogger.debug(LTag.PUMP, "Acknowledge alerts result: {} ({})", result.success, result.comment); @@ -827,7 +827,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa @Override public PumpEnactResult executeCustomCommand(@NonNull CustomCommand command) { - if (command instanceof CommandAcknowledgeAlerts) { + if (command instanceof CommandSilenceAlerts) { return executeCommand(OmnipodCommandType.ACKNOWLEDGE_ALERTS, aapsOmnipodErosManager::acknowledgeAlerts); } if (command instanceof CommandGetPodStatus) { diff --git a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/OmnipodErosOverviewFragment.kt b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/OmnipodErosOverviewFragment.kt index 8834725c26..804e513455 100644 --- a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/OmnipodErosOverviewFragment.kt +++ b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/OmnipodErosOverviewFragment.kt @@ -24,7 +24,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLin import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewButtonsBinding import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewPodInfoBinding -import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandAcknowledgeAlerts +import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery @@ -148,7 +148,8 @@ class OmnipodErosOverviewFragment : DaggerFragment() { buttonBinding.buttonSilenceAlerts.setOnClickListener { disablePodActionButtons() - commandQueue.customCommand(CommandAcknowledgeAlerts(), + commandQueue.customCommand( + CommandSilenceAlerts(), DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts), false) .messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_silenced_alerts)) .actionOnSuccess { rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_ALERTS)) }) @@ -513,7 +514,8 @@ class OmnipodErosOverviewFragment : DaggerFragment() { } private fun updateSilenceAlertsButton() { - if (!omnipodManager.isAutomaticallyAcknowledgeAlertsEnabled && podStateManager.isPodRunning && (podStateManager.hasActiveAlerts() || commandQueue.isCustomCommandInQueue(CommandAcknowledgeAlerts::class.java))) { + if (!omnipodManager.isAutomaticallyAcknowledgeAlertsEnabled && podStateManager.isPodRunning && (podStateManager.hasActiveAlerts() || commandQueue.isCustomCommandInQueue( + CommandSilenceAlerts::class.java))) { buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE buttonBinding.buttonSilenceAlerts.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } else { diff --git a/omnipod-eros/src/main/res/layout/omnipod_eros_pod_management.xml b/omnipod-eros/src/main/res/layout/omnipod_eros_pod_management.xml index a6262966e3..4aa7408086 100644 --- a/omnipod-eros/src/main/res/layout/omnipod_eros_pod_management.xml +++ b/omnipod-eros/src/main/res/layout/omnipod_eros_pod_management.xml @@ -14,7 +14,6 @@ android:orientation="vertical"> - -