Merge pull request #29 from 0pen-dash/andrei/confirm-deny-command
Andrei/confirm deny command
This commit is contained in:
commit
c19989d649
22 changed files with 379 additions and 260 deletions
|
@ -31,7 +31,8 @@ class DeactivatePodFragment : ActionFragmentBase() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
view.findViewById<Button>(R.id.omnipod_wizard_button_discard_pod)?.setOnClickListener {
|
||||
buttonDiscardPod = view.findViewById(R.id.omnipod_wizard_button_discard_pod)
|
||||
buttonDiscardPod.setOnClickListener {
|
||||
context?.let {
|
||||
AlertDialog.Builder(it)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
|
|
|
@ -11,18 +11,25 @@ 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.definition.OmnipodCommandType
|
||||
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.event.PodEvent
|
||||
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.history.DashHistory
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusRecord
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.TempBasalRecord
|
||||
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.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.rxkotlin.blockingSubscribeBy
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
|
@ -37,6 +44,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
private val podStateManager: OmnipodDashPodStateManager,
|
||||
private val sp: SP,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val history: DashHistory,
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
resourceHelper: ResourceHelper,
|
||||
|
@ -72,8 +80,23 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun isConnected(): Boolean {
|
||||
// TODO
|
||||
return true
|
||||
// NOTE: Using connected state for unconfirmed commands
|
||||
|
||||
// We are faking connection lost on unconfirmed commands.
|
||||
// During normal execution, the activeCommand is set to null after a command was executed with success or we
|
||||
// were not able to send that command.
|
||||
// If we are not sure if the POD received the command or not, then we answer with "success" but keep this
|
||||
// activeCommand set until we can confirm/deny it.
|
||||
|
||||
// In order to prevent AAPS from sending us other programming commands while the current command was not
|
||||
// confirmed, we are simulating "connection lost".
|
||||
// We need to prevent AAPS from sending other commands because they would overwrite the ID of the last
|
||||
// programming command reported by the POD. And we using that ID to confirm/deny the activeCommand.
|
||||
|
||||
// The effect of answering with 'false' here is that AAPS will call connect() and will not sent any new
|
||||
// commands. On connect(), we are calling getPodStatus where we are always trying to confirm/deny the
|
||||
// activeCommand.
|
||||
return podStateManager.activeCommand == null
|
||||
}
|
||||
|
||||
override fun isConnecting(): Boolean {
|
||||
|
@ -91,7 +114,12 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun connect(reason: String) {
|
||||
// TODO
|
||||
// See:
|
||||
// NOTE: Using connected state for unconfirmed commands
|
||||
if (podStateManager.activeCommand == null) {
|
||||
return
|
||||
}
|
||||
getPumpStatus("unconfirmed command")
|
||||
}
|
||||
|
||||
override fun disconnect(reason: String) {
|
||||
|
@ -103,8 +131,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun getPumpStatus(reason: String) {
|
||||
// TODO history
|
||||
omnipodManager.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE).blockingSubscribeBy(
|
||||
Observable.concat(
|
||||
omnipodManager.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE),
|
||||
history.updateFromState(podStateManager).toObservable(),
|
||||
podStateManager.updateActiveCommand().toObservable(),
|
||||
).blockingSubscribeBy(
|
||||
onNext = { podEvent ->
|
||||
aapsLogger.debug(
|
||||
LTag.PUMP,
|
||||
|
@ -121,35 +152,20 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||
// TODO history
|
||||
|
||||
return Single.create<PumpEnactResult> { 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()
|
||||
return executeProgrammingCommand(
|
||||
history.createRecord(
|
||||
commandType = OmnipodCommandType.SET_BASAL_PROFILE
|
||||
),
|
||||
omnipodManager.setBasalProgram(mapProfileToBasalProgram(profile))
|
||||
)
|
||||
}
|
||||
|
||||
override fun isThisProfileSet(profile: Profile): Boolean = podStateManager.basalProgram?.let {
|
||||
it == mapProfileToBasalProgram(profile)
|
||||
} ?: true
|
||||
|
||||
|
||||
override fun lastDataTime(): Long {
|
||||
return podStateManager.lastConnection
|
||||
return podStateManager.lastUpdatedSystem
|
||||
}
|
||||
|
||||
override val baseBasalRate: Double
|
||||
|
@ -172,7 +188,6 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
get() = 0
|
||||
|
||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||
// TODO history
|
||||
// TODO update Treatments (?)
|
||||
// TODO bolus progress
|
||||
// TODO report actual delivered amount after Pod Alarm and bolus cancellation
|
||||
|
@ -180,10 +195,23 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
return Single.create<PumpEnactResult> { source ->
|
||||
val bolusBeeps = sp.getBoolean(R.string.key_omnipod_common_bolus_beeps_enabled, false)
|
||||
|
||||
omnipodManager.bolus(
|
||||
detailedBolusInfo.insulin,
|
||||
bolusBeeps,
|
||||
bolusBeeps
|
||||
Observable.concat(
|
||||
history.createRecord(
|
||||
commandType = OmnipodCommandType.SET_BOLUS,
|
||||
bolusRecord = BolusRecord(
|
||||
detailedBolusInfo.insulin,
|
||||
if (detailedBolusInfo.isSMB) BolusType.SMB else BolusType.DEFAULT
|
||||
),
|
||||
).flatMapObservable { recordId ->
|
||||
podStateManager.createActiveCommand(recordId).toObservable()
|
||||
},
|
||||
omnipodManager.bolus(
|
||||
detailedBolusInfo.insulin,
|
||||
bolusBeeps,
|
||||
bolusBeeps
|
||||
),
|
||||
history.updateFromState(podStateManager).toObservable(),
|
||||
podStateManager.updateActiveCommand().toObservable(),
|
||||
).subscribeBy(
|
||||
onNext = { podEvent ->
|
||||
aapsLogger.debug(
|
||||
|
@ -193,12 +221,15 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
},
|
||||
onError = { throwable ->
|
||||
aapsLogger.error(LTag.PUMP, "Error in deliverTreatment", throwable)
|
||||
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
|
||||
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)
|
||||
PumpEnactResult(injector).success(true).enacted(true)
|
||||
.bolusDelivered(detailedBolusInfo.insulin)
|
||||
.carbsDelivered(detailedBolusInfo.carbs)
|
||||
)
|
||||
}
|
||||
|
@ -207,22 +238,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun stopBolusDelivering() {
|
||||
// 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")
|
||||
}
|
||||
executeProgrammingCommand(
|
||||
history.createRecord(OmnipodCommandType.CANCEL_BOLUS),
|
||||
omnipodManager.stopBolus(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -232,33 +251,24 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
profile: Profile,
|
||||
enforceNew: Boolean
|
||||
): PumpEnactResult {
|
||||
// TODO history
|
||||
// TODO update Treatments
|
||||
|
||||
return Single.create<PumpEnactResult> { source ->
|
||||
// TODO check for existing basal
|
||||
// check existing basal(locally and maybe? get status)
|
||||
// if enforceNew -> cancel it()
|
||||
// else -> return error that existing basal is running
|
||||
// set new temp basal
|
||||
// update treatments
|
||||
// profit
|
||||
return executeProgrammingCommand(
|
||||
history.createRecord(
|
||||
commandType = OmnipodCommandType.SET_TEMPORARY_BASAL,
|
||||
tempBasalRecord = TempBasalRecord(duration = durationInMinutes, rate = absoluteRate)
|
||||
),
|
||||
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(
|
||||
|
@ -279,29 +289,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||
// TODO history
|
||||
// TODO update Treatments
|
||||
|
||||
return Single.create<PumpEnactResult> { 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()
|
||||
return executeProgrammingCommand(
|
||||
history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL),
|
||||
omnipodManager.stopTempBasal()
|
||||
)
|
||||
}
|
||||
|
||||
override fun cancelExtendedBolus(): PumpEnactResult {
|
||||
|
@ -326,11 +318,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun serialNumber(): String {
|
||||
return if (podStateManager.uniqueId == null) {
|
||||
"n/a" // TODO i18n
|
||||
} else {
|
||||
podStateManager.uniqueId.toString()
|
||||
}
|
||||
return podStateManager.uniqueId?.toString()
|
||||
?: "n/a" // TODO i18n
|
||||
}
|
||||
|
||||
override fun shortStatus(veryShort: Boolean): String {
|
||||
|
@ -389,12 +378,15 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
private fun silenceAlerts(): PumpEnactResult {
|
||||
// TODO history
|
||||
// TODO filter alert types
|
||||
|
||||
return podStateManager.activeAlerts?.let {
|
||||
Single.create<PumpEnactResult> { source ->
|
||||
omnipodManager.silenceAlerts(it).subscribeBy(
|
||||
Observable.concat(
|
||||
// TODO: is this a programming command? if yes, save to history
|
||||
omnipodManager.silenceAlerts(it),
|
||||
history.updateFromState(podStateManager).toObservable(),
|
||||
podStateManager.updateActiveCommand().toObservable(),
|
||||
).subscribeBy(
|
||||
onNext = { podEvent ->
|
||||
aapsLogger.debug(
|
||||
LTag.PUMP,
|
||||
|
@ -415,75 +407,26 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
private fun suspendDelivery(): PumpEnactResult {
|
||||
// TODO history
|
||||
|
||||
return Single.create<PumpEnactResult> { 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()
|
||||
return executeProgrammingCommand(
|
||||
history.createRecord(OmnipodCommandType.RESUME_DELIVERY),
|
||||
omnipodManager.suspendDelivery()
|
||||
)
|
||||
}
|
||||
|
||||
private fun resumeDelivery(): PumpEnactResult {
|
||||
// TODO history
|
||||
|
||||
return profileFunction.getProfile()?.let {
|
||||
|
||||
Single.create<PumpEnactResult> { 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()
|
||||
executeProgrammingCommand(
|
||||
history.createRecord(OmnipodCommandType.RESUME_DELIVERY),
|
||||
omnipodManager.setBasalProgram(mapProfileToBasalProgram(it))
|
||||
)
|
||||
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n
|
||||
}
|
||||
|
||||
private fun deactivatePod(): PumpEnactResult {
|
||||
// TODO history
|
||||
|
||||
return Single.create<PumpEnactResult> { 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()
|
||||
return executeProgrammingCommand(
|
||||
history.createRecord(OmnipodCommandType.DEACTIVATE_POD),
|
||||
omnipodManager.deactivatePod()
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleTimeChange(): PumpEnactResult {
|
||||
|
@ -497,28 +440,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
private fun playTestBeep(): PumpEnactResult {
|
||||
// TODO history
|
||||
|
||||
return Single.create<PumpEnactResult> { 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()
|
||||
return executeProgrammingCommand(
|
||||
history.createRecord(OmnipodCommandType.PLAY_TEST_BEEP),
|
||||
omnipodManager.playBeep(BeepType.LONG_SINGLE_BEEP)
|
||||
)
|
||||
}
|
||||
|
||||
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
|
||||
|
@ -541,4 +466,51 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
|
||||
commandQueue.customCommand(CommandHandleTimeChange(false), null)
|
||||
}
|
||||
|
||||
private fun observeAddNewActiveCommandToHistory(observeCreateHistoryEntry: Single<String>): Observable<PodEvent> {
|
||||
return observeCreateHistoryEntry.flatMapObservable {
|
||||
podStateManager.createActiveCommand(it).toObservable<PodEvent>()
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeProgrammingCommand(
|
||||
observeCreateHistoryEntry: Single<String>,
|
||||
command: Observable<PodEvent>
|
||||
): PumpEnactResult {
|
||||
return Single.create<PumpEnactResult> { source ->
|
||||
Observable.concat(
|
||||
listOf(
|
||||
podStateManager.observeNoActiveCommand(),
|
||||
observeAddNewActiveCommandToHistory(observeCreateHistoryEntry),
|
||||
command,
|
||||
history.updateFromState(podStateManager).toObservable(),
|
||||
podStateManager.updateActiveCommand().toObservable(),
|
||||
)
|
||||
).subscribeBy(
|
||||
onNext = { podEvent ->
|
||||
aapsLogger.debug(
|
||||
LTag.PUMP,
|
||||
"Received PodEvent: $podEvent"
|
||||
)
|
||||
},
|
||||
onError = { throwable ->
|
||||
aapsLogger.error(LTag.PUMP, "Error executing command", throwable)
|
||||
// Here we assume that onError will be called only BEFORE we manage to send a command
|
||||
// If it gets called later, we will have the command as "not sent" in history and will not try to
|
||||
// get it's final status, even if it was send
|
||||
|
||||
podStateManager.maybeMarkActiveCommandFailed()
|
||||
source.onSuccess(
|
||||
PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message)
|
||||
)
|
||||
},
|
||||
onComplete = {
|
||||
aapsLogger.debug("Command completed")
|
||||
source.onSuccess(
|
||||
PumpEnactResult(injector).success(true).enacted(true)
|
||||
)
|
||||
}
|
||||
)
|
||||
}.blockingGet()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver
|
||||
|
||||
import android.os.SystemClock
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager
|
||||
|
@ -643,6 +644,20 @@ class OmnipodDashManagerImpl @Inject constructor(
|
|||
}
|
||||
|
||||
is PodEvent.CommandSent -> {
|
||||
podStateManager.activeCommand?.let {
|
||||
if (it.sequence == event.command.sequenceNumber) {
|
||||
it.sentRealtime = SystemClock.elapsedRealtime()
|
||||
}
|
||||
}
|
||||
podStateManager.increaseMessageSequenceNumber()
|
||||
}
|
||||
|
||||
is PodEvent.CommandSendNotConfirmed -> {
|
||||
podStateManager.activeCommand?.let {
|
||||
if (it.sequence == event.command.sequenceNumber) {
|
||||
it.sentRealtime = SystemClock.elapsedRealtime()
|
||||
}
|
||||
}
|
||||
podStateManager.increaseMessageSequenceNumber()
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm
|
|||
import info.nightscout.androidaps.utils.extensions.toHex
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
|
||||
data class Id(val address: ByteArray) {
|
||||
init {
|
||||
require(address.size == 4)
|
||||
|
|
|
@ -17,4 +17,4 @@ class Ids(podState: OmnipodDashPodStateManager) {
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
|||
val conn = assertConnected()
|
||||
return conn.session
|
||||
?: throw NotConnectedException("Missing session")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStatus(): ConnectionStatus {
|
||||
// TODO is this used?
|
||||
|
|
|
@ -42,7 +42,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) {
|
|||
oneExtraPacket = lastPacket.oneExtraPacket
|
||||
}
|
||||
|
||||
idx == fullFragments+1 && oneExtraPacket -> {
|
||||
idx == fullFragments + 1 && oneExtraPacket -> {
|
||||
fragments.add(LastOptionalPlusOneBlePacket.parse(packet))
|
||||
}
|
||||
|
||||
|
|
|
@ -2,15 +2,12 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair
|
|||
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Ids
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.MessageIOException
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.PairingException
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageSendErrorSending
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageSendSuccess
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding.Companion.parseKeys
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.RandomByteGenerator
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.X25519KeyGenerator
|
||||
|
@ -35,7 +32,7 @@ internal class LTKExchanger(
|
|||
keys = arrayOf(SP1, SP2),
|
||||
payloads = arrayOf(ids.podId.address, sp2())
|
||||
)
|
||||
throwOnSendError(sp1sp2.messagePacket, SP1+SP2)
|
||||
throwOnSendError(sp1sp2.messagePacket, SP1 + SP2)
|
||||
|
||||
seq++
|
||||
val sps1 = PairMessage(
|
||||
|
@ -67,16 +64,16 @@ internal class LTKExchanger(
|
|||
|
||||
seq++
|
||||
// send SP0GP0
|
||||
val sp0gp0 = PairMessage (
|
||||
sequenceNumber = seq,
|
||||
source = ids.myId,
|
||||
destination = podAddress,
|
||||
keys = arrayOf(SP0GP0),
|
||||
payloads = arrayOf(ByteArray(0))
|
||||
)
|
||||
val sp0gp0 = PairMessage(
|
||||
sequenceNumber = seq,
|
||||
source = ids.myId,
|
||||
destination = podAddress,
|
||||
keys = arrayOf(SP0GP0),
|
||||
payloads = arrayOf(ByteArray(0))
|
||||
)
|
||||
val result = msgIO.sendMessage(sp0gp0.messagePacket)
|
||||
if (result !is MessageSendSuccess) {
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM,"Error sending SP0GP0: $result")
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Error sending SP0GP0: $result")
|
||||
}
|
||||
|
||||
msgIO.receiveMessage()
|
||||
|
@ -97,7 +94,6 @@ internal class LTKExchanger(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun processSps1FromPod(msg: MessagePacket) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Received SPS1 from pod: ${msg.payload.toHex()}")
|
||||
|
||||
|
|
|
@ -86,8 +86,10 @@ class Connection(
|
|||
val msgIO = MessageIO(aapsLogger, cmdBleIO, dataBleIO)
|
||||
|
||||
fun connect() {
|
||||
disconnect()
|
||||
|
||||
if (session != null) {
|
||||
disconnect()
|
||||
}
|
||||
aapsLogger.debug("Connecting")
|
||||
if (!gattConnection.connect()) {
|
||||
throw FailedToConnectException("connect() returned false")
|
||||
}
|
||||
|
@ -167,6 +169,6 @@ class Connection(
|
|||
|
||||
companion object {
|
||||
|
||||
private const val CONNECT_TIMEOUT_MS = 7000
|
||||
private const val CONNECT_TIMEOUT_MS = 12000
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
|||
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Ids
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.EnDecrypt
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotParseResponseException
|
||||
|
|
|
@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
|||
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Ids
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.Nonce
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.SessionEstablishmentException
|
||||
|
|
|
@ -65,4 +65,6 @@ sealed class PodEvent {
|
|||
return "ResponseReceived(command=$command, response=$response)"
|
||||
}
|
||||
}
|
||||
|
||||
data class CommandConfirmed(val historyId: String, val success: Boolean) : PodEvent()
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class ProgramBasalCommand private constructor(
|
|||
private val delayUntilNextTenthPulseInUsec: Int
|
||||
val length: Short
|
||||
get() = (insulinProgramElements.size * 6 + 10).toShort()
|
||||
val bodyLength: Byte
|
||||
private val bodyLength: Byte
|
||||
get() = (insulinProgramElements.size * 6 + 8).toByte()
|
||||
|
||||
override val encoded: ByteArray
|
||||
|
|
|
@ -6,4 +6,5 @@ import java.io.Serializable
|
|||
interface Command : Encodable, Serializable {
|
||||
|
||||
val commandType: CommandType
|
||||
val sequenceNumber: Short
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.nio.ByteBuffer
|
|||
abstract class HeaderEnabledCommand protected constructor(
|
||||
override val commandType: CommandType,
|
||||
protected val uniqueId: Int,
|
||||
protected val sequenceNumber: Short,
|
||||
override val sequenceNumber: Short,
|
||||
protected val multiCommandFlag: Boolean
|
||||
) : Command {
|
||||
|
||||
|
|
|
@ -2,11 +2,15 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state
|
|||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.PairResult
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.SetUniqueIdResponse
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Observable
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
|
@ -18,7 +22,9 @@ interface OmnipodDashPodStateManager {
|
|||
val isSuspended: Boolean
|
||||
val isPodRunning: Boolean
|
||||
var lastConnection: Long
|
||||
val lastUpdated: Long
|
||||
|
||||
val lastUpdatedSystem: Long // System.currentTimeMillis()
|
||||
val lastStatusResponseReceived: Long
|
||||
|
||||
val messageSequenceNumber: Short
|
||||
val sequenceNumberOfLastProgrammingCommand: Short?
|
||||
|
@ -48,6 +54,7 @@ interface OmnipodDashPodStateManager {
|
|||
val tempBasal: TempBasal?
|
||||
val tempBasalActive: Boolean
|
||||
var basalProgram: BasalProgram?
|
||||
val activeCommand: ActiveCommand?
|
||||
|
||||
fun increaseMessageSequenceNumber()
|
||||
fun increaseEapAkaSequenceNumber(): ByteArray
|
||||
|
@ -59,5 +66,17 @@ interface OmnipodDashPodStateManager {
|
|||
fun updateFromPairing(uniqueId: Id, pairResult: PairResult)
|
||||
fun reset()
|
||||
|
||||
fun createActiveCommand(historyId: String): Completable
|
||||
fun updateActiveCommand(): Maybe<PodEvent>
|
||||
fun observeNoActiveCommand(): Observable<PodEvent>
|
||||
fun maybeMarkActiveCommandFailed()
|
||||
|
||||
data class ActiveCommand(
|
||||
val sequence: Short,
|
||||
val createdRealtime: Long,
|
||||
var sentRealtime: Long = 0,
|
||||
val historyId: String
|
||||
)
|
||||
// TODO: set created to "now" on boot
|
||||
data class TempBasal(val startTime: Long, val rate: Double, val durationInMinutes: Short) : Serializable
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state
|
||||
|
||||
import android.os.SystemClock
|
||||
import com.google.gson.Gson
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
|
@ -9,12 +10,16 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.PairResult
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.EapSqn
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.SetUniqueIdResponse
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Observable
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -60,8 +65,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
store()
|
||||
}
|
||||
|
||||
override val lastUpdated: Long
|
||||
get() = podState.lastUpdated
|
||||
override val lastUpdatedSystem: Long
|
||||
get() = podState.lastUpdatedSystem
|
||||
|
||||
override val messageSequenceNumber: Short
|
||||
get() = podState.messageSequenceNumber
|
||||
|
@ -152,6 +157,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
store()
|
||||
}
|
||||
|
||||
override val lastStatusResponseReceived: Long
|
||||
get() = podState.lastStatusResponseReceived
|
||||
|
||||
override fun increaseMessageSequenceNumber() {
|
||||
podState.messageSequenceNumber = ((podState.messageSequenceNumber.toInt() + 1) and 0x0f).toShort()
|
||||
store()
|
||||
|
@ -171,6 +179,76 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
store()
|
||||
}
|
||||
|
||||
override val activeCommand: OmnipodDashPodStateManager.ActiveCommand?
|
||||
get() = podState.activeCommand
|
||||
|
||||
@Synchronized
|
||||
override fun createActiveCommand(historyId: String) = Completable.create { source ->
|
||||
if (activeCommand == null) {
|
||||
podState.activeCommand = OmnipodDashPodStateManager.ActiveCommand(
|
||||
podState.messageSequenceNumber,
|
||||
createdRealtime = SystemClock.elapsedRealtime(),
|
||||
historyId = historyId
|
||||
)
|
||||
source.onComplete()
|
||||
} else {
|
||||
source.onError(
|
||||
java.lang.IllegalStateException(
|
||||
"Trying to send a command " +
|
||||
"and the last command was not confirmed"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun observeNoActiveCommand(): Observable<PodEvent> {
|
||||
return Observable.defer {
|
||||
if (activeCommand == null) {
|
||||
Observable.empty()
|
||||
} else {
|
||||
Observable.error(
|
||||
java.lang.IllegalStateException(
|
||||
"Trying to send a command " +
|
||||
"and the last command was not confirmed"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun maybeMarkActiveCommandFailed() {
|
||||
podState.activeCommand?.run {
|
||||
if (sentRealtime < createdRealtime) {
|
||||
// command was not sent
|
||||
podState.activeCommand = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun updateActiveCommand() = Maybe.create<PodEvent> { source ->
|
||||
podState.activeCommand?.run {
|
||||
logger.debug(
|
||||
"Trying to confirm active command with parameters: $activeCommand " +
|
||||
"lastResponse=$lastStatusResponseReceived " +
|
||||
"$sequenceNumberOfLastProgrammingCommand $historyId"
|
||||
)
|
||||
if (createdRealtime >= lastStatusResponseReceived)
|
||||
// we did not receive a valid response yet
|
||||
source.onComplete()
|
||||
else {
|
||||
podState.activeCommand = null
|
||||
if (sequenceNumberOfLastProgrammingCommand == sequence)
|
||||
source.onSuccess(PodEvent.CommandConfirmed(historyId, true))
|
||||
else
|
||||
source.onSuccess(PodEvent.CommandConfirmed(historyId, false))
|
||||
}
|
||||
}
|
||||
?: source.onComplete() // no active programming command
|
||||
}
|
||||
|
||||
override fun increaseEapAkaSequenceNumber(): ByteArray {
|
||||
podState.eapAkaSequenceNumber++
|
||||
return EapSqn(podState.eapAkaSequenceNumber).value
|
||||
|
@ -191,7 +269,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
podState.minutesSinceActivation = response.minutesSinceActivation
|
||||
podState.activeAlerts = response.activeAlerts
|
||||
|
||||
podState.lastUpdated = System.currentTimeMillis()
|
||||
podState.lastUpdatedSystem = System.currentTimeMillis()
|
||||
podState.lastStatusResponseReceived = SystemClock.elapsedRealtime()
|
||||
|
||||
store()
|
||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||
}
|
||||
|
@ -211,7 +291,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
podState.lotNumber = response.lotNumber
|
||||
podState.podSequenceNumber = response.podSequenceNumber
|
||||
|
||||
podState.lastUpdated = System.currentTimeMillis()
|
||||
podState.lastUpdatedSystem = System.currentTimeMillis()
|
||||
|
||||
store()
|
||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||
}
|
||||
|
@ -237,7 +318,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
podState.podSequenceNumber = response.podSequenceNumber
|
||||
podState.uniqueId = response.uniqueIdReceivedInCommand
|
||||
|
||||
podState.lastUpdated = System.currentTimeMillis()
|
||||
podState.lastUpdatedSystem = System.currentTimeMillis()
|
||||
|
||||
store()
|
||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||
}
|
||||
|
@ -293,7 +375,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
|
||||
var activationProgress: ActivationProgress = ActivationProgress.NOT_STARTED
|
||||
var lastConnection: Long = 0
|
||||
var lastUpdated: Long = 0
|
||||
var lastUpdatedSystem: Long = 0
|
||||
var lastStatusResponseReceived: Long = 0
|
||||
|
||||
var messageSequenceNumber: Short = 0
|
||||
var sequenceNumberOfLastProgrammingCommand: Short? = null
|
||||
|
@ -322,5 +405,6 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
|
||||
var basalProgram: BasalProgram? = null
|
||||
var tempBasal: OmnipodDashPodStateManager.TempBasal? = null
|
||||
var activeCommand: OmnipodDashPodStateManager.ActiveCommand? = null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.github.guepardoapps.kulid.ULID
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_BOLUS
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_TEMPORARY_BASAL
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusRecord
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.HistoryRecord
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.InitialResult
|
||||
|
@ -22,13 +23,13 @@ class DashHistory @Inject constructor(
|
|||
private val historyMapper: HistoryMapper
|
||||
) {
|
||||
|
||||
fun markSuccess(id: String, date: Long): Completable = dao.markResolved(
|
||||
private fun markSuccess(id: String): Completable = dao.markResolved(
|
||||
id,
|
||||
ResolvedResult.SUCCESS,
|
||||
currentTimeMillis()
|
||||
)
|
||||
|
||||
fun markFailure(id: String, date: Long): Completable = dao.markResolved(
|
||||
private fun markFailure(id: String): Completable = dao.markResolved(
|
||||
id,
|
||||
ResolvedResult.FAILURE,
|
||||
currentTimeMillis()
|
||||
|
@ -37,8 +38,8 @@ class DashHistory @Inject constructor(
|
|||
@Suppress("ReturnCount")
|
||||
fun createRecord(
|
||||
commandType: OmnipodCommandType,
|
||||
date: Long,
|
||||
initialResult: InitialResult = InitialResult.UNCONFIRMED,
|
||||
date: Long = System.currentTimeMillis(),
|
||||
initialResult: InitialResult = InitialResult.NOT_SENT,
|
||||
tempBasalRecord: TempBasalRecord? = null,
|
||||
bolusRecord: BolusRecord? = null,
|
||||
resolveResult: ResolvedResult? = null,
|
||||
|
@ -72,4 +73,29 @@ class DashHistory @Inject constructor(
|
|||
dao.all().map { list -> list.map(historyMapper::entityToDomain) }
|
||||
|
||||
fun getRecordsAfter(time: Long): Single<List<HistoryRecordEntity>> = dao.allSince(time)
|
||||
|
||||
fun updateFromState(podState: OmnipodDashPodStateManager) = Completable.defer {
|
||||
podState.activeCommand?.run {
|
||||
when {
|
||||
|
||||
createdRealtime <= podState.lastStatusResponseReceived &&
|
||||
sequence == podState.sequenceNumberOfLastProgrammingCommand ->
|
||||
dao.setInitialResult(historyId, InitialResult.SENT)
|
||||
.andThen(markSuccess(historyId))
|
||||
|
||||
createdRealtime <= podState.lastStatusResponseReceived &&
|
||||
sequence != podState.sequenceNumberOfLastProgrammingCommand ->
|
||||
markFailure(historyId)
|
||||
|
||||
// no response received after this point
|
||||
createdRealtime <= sentRealtime ->
|
||||
dao.setInitialResult(historyId, InitialResult.SENT)
|
||||
|
||||
createdRealtime > sentRealtime ->
|
||||
dao.setInitialResult(historyId, InitialResult.FAILURE_SENDING)
|
||||
|
||||
else -> Completable.error(IllegalStateException("This can't happen. Could not update history"))
|
||||
}
|
||||
} ?: Completable.complete() // no active programming command
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ sealed class Record
|
|||
|
||||
data class BolusRecord(val amout: Double, val bolusType: BolusType) : Record()
|
||||
|
||||
data class TempBasalRecord(val duration: Long, val rate: Double) : Record()
|
||||
data class TempBasalRecord(val duration: Int, val rate: Double) : Record()
|
||||
|
||||
enum class BolusType {
|
||||
DEFAULT, SMB
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data
|
||||
|
||||
enum class InitialResult {
|
||||
SUCCESS, FAILURE, UNCONFIRMED
|
||||
NOT_SENT, FAILURE_SENDING, UNCONFIRMED, SENT
|
||||
}
|
||||
|
||||
enum class ResolvedResult {
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.room.Delete
|
|||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.InitialResult
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.ResolvedResult
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
|
@ -32,4 +33,7 @@ abstract class HistoryRecordDao {
|
|||
|
||||
@Query("UPDATE historyrecords SET resolvedResult = :resolvedResult, resolvedAt = :resolvedAt WHERE id = :id ")
|
||||
abstract fun markResolved(id: String, resolvedResult: ResolvedResult, resolvedAt: Long): Completable
|
||||
|
||||
@Query("UPDATE historyrecords SET initialResult = :initialResult WHERE id = :id ")
|
||||
abstract fun setInitialResult(id: String, initialResult: InitialResult): Completable
|
||||
}
|
||||
|
|
|
@ -28,25 +28,25 @@ class DefaultStatusResponseTest {
|
|||
|
||||
/**
|
||||
* response (hex) 08202EAA0C0A1D1905281000004387D3039A
|
||||
Status response: 29
|
||||
Pod status: RUNNING_BELOW_MIN_VOLUME
|
||||
Basal active: true
|
||||
Temp Basal active: false
|
||||
Immediate bolus active: false
|
||||
Extended bolus active: false
|
||||
Bolus pulses remaining: 0
|
||||
sequence number of last programing command: 2
|
||||
Total full pulses delivered: 2640
|
||||
Full reservoir pulses remaining: 979
|
||||
Time since activation: 4321
|
||||
Alert 1 is InActive
|
||||
Alert 2 is InActive
|
||||
Alert 3 is InActive
|
||||
Alert 4 is InActive
|
||||
Alert 5 is InActive
|
||||
Alert 6 is InActive
|
||||
Alert 7 is InActive
|
||||
Occlusion alert active false
|
||||
Status response: 29
|
||||
Pod status: RUNNING_BELOW_MIN_VOLUME
|
||||
Basal active: true
|
||||
Temp Basal active: false
|
||||
Immediate bolus active: false
|
||||
Extended bolus active: false
|
||||
Bolus pulses remaining: 0
|
||||
sequence number of last programing command: 2
|
||||
Total full pulses delivered: 2640
|
||||
Full reservoir pulses remaining: 979
|
||||
Time since activation: 4321
|
||||
Alert 1 is InActive
|
||||
Alert 2 is InActive
|
||||
Alert 3 is InActive
|
||||
Alert 4 is InActive
|
||||
Alert 5 is InActive
|
||||
Alert 6 is InActive
|
||||
Alert 7 is InActive
|
||||
Occlusion alert active false
|
||||
*/
|
||||
@Test @Throws(DecoderException::class) fun testValidResponseBelowMin() {
|
||||
val encoded = Hex.decodeHex("1D1905281000004387D3039A")
|
||||
|
@ -67,25 +67,25 @@ class DefaultStatusResponseTest {
|
|||
|
||||
/**
|
||||
* response (hex) 08202EAA080A1D180519C00E0039A7FF8085
|
||||
Status response: 29
|
||||
Pod status: RUNNING_ABOVE_MIN_VOLUME
|
||||
Basal active: true
|
||||
Temp Basal active: false
|
||||
Immediate bolus active: false
|
||||
Extended bolus active: false
|
||||
Bolus pulses remaining: 14
|
||||
sequence number of last programing command: 8
|
||||
Total full pulses delivered: 2611
|
||||
Full reservoir pulses remaining: 1023
|
||||
Time since activation: 3689
|
||||
Alert 1 is InActive
|
||||
Alert 2 is InActive
|
||||
Alert 3 is InActive
|
||||
Alert 4 is InActive
|
||||
Alert 5 is InActive
|
||||
Alert 6 is InActive
|
||||
Alert 7 is InActive
|
||||
Occlusion alert active false
|
||||
Status response: 29
|
||||
Pod status: RUNNING_ABOVE_MIN_VOLUME
|
||||
Basal active: true
|
||||
Temp Basal active: false
|
||||
Immediate bolus active: false
|
||||
Extended bolus active: false
|
||||
Bolus pulses remaining: 14
|
||||
sequence number of last programing command: 8
|
||||
Total full pulses delivered: 2611
|
||||
Full reservoir pulses remaining: 1023
|
||||
Time since activation: 3689
|
||||
Alert 1 is InActive
|
||||
Alert 2 is InActive
|
||||
Alert 3 is InActive
|
||||
Alert 4 is InActive
|
||||
Alert 5 is InActive
|
||||
Alert 6 is InActive
|
||||
Alert 7 is InActive
|
||||
Occlusion alert active false
|
||||
*/
|
||||
@Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining() {
|
||||
val encoded = Hex.decodeHex("1D180519C00E0039A7FF8085")
|
||||
|
|
Loading…
Reference in a new issue