Patch activation flow
This commit is contained in:
parent
af6445a3dc
commit
fff833dae3
26 changed files with 720 additions and 116 deletions
|
@ -8,6 +8,7 @@ import android.os.IBinder
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.core.ui.toast.ToastUtils
|
import info.nightscout.core.ui.toast.ToastUtils
|
||||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||||
|
import info.nightscout.interfaces.notifications.Notification
|
||||||
import info.nightscout.interfaces.plugin.PluginDescription
|
import info.nightscout.interfaces.plugin.PluginDescription
|
||||||
import info.nightscout.interfaces.plugin.PluginType
|
import info.nightscout.interfaces.plugin.PluginType
|
||||||
import info.nightscout.interfaces.profile.Profile
|
import info.nightscout.interfaces.profile.Profile
|
||||||
|
@ -33,6 +34,7 @@ import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventAppExit
|
import info.nightscout.rx.events.EventAppExit
|
||||||
import info.nightscout.rx.events.EventAppInitialized
|
import info.nightscout.rx.events.EventAppInitialized
|
||||||
|
import info.nightscout.rx.events.EventDismissNotification
|
||||||
import info.nightscout.rx.events.EventOverviewBolusProgress
|
import info.nightscout.rx.events.EventOverviewBolusProgress
|
||||||
import info.nightscout.rx.events.EventPreferenceChange
|
import info.nightscout.rx.events.EventPreferenceChange
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
@ -170,11 +172,33 @@ class MedtrumPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||||
return PumpEnactResult(injector).success(true).enacted(true) // TODO
|
// New profile will be set when patch is activated
|
||||||
|
if (!isInitialized()) return PumpEnactResult(injector).success(true).enacted(true)
|
||||||
|
|
||||||
|
return if (medtrumService?.updateBasalsInPump(profile) == true) {
|
||||||
|
rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE))
|
||||||
|
uiInteraction.addNotificationValidFor(Notification.PROFILE_SET_OK, rh.gs(info.nightscout.core.ui.R.string.profile_set_ok), Notification.INFO, 60)
|
||||||
|
PumpEnactResult(injector).success(true).enacted(true)
|
||||||
|
} else {
|
||||||
|
uiInteraction.addNotification(Notification.FAILED_UPDATE_PROFILE, rh.gs(info.nightscout.core.ui.R.string.failed_update_basal_profile), Notification.URGENT)
|
||||||
|
PumpEnactResult(injector)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||||
return false // TODO
|
if (!isInitialized()) return true
|
||||||
|
var result = false
|
||||||
|
val profileBytes = medtrumPump.buildMedtrumProfileArray(profile)
|
||||||
|
if (profileBytes?.size == medtrumPump.actualBasalProfile.size) {
|
||||||
|
result = true
|
||||||
|
for (i in profileBytes.indices) {
|
||||||
|
if (profileBytes[i] != medtrumPump.actualBasalProfile[i]) {
|
||||||
|
result = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lastDataTime(): Long {
|
override fun lastDataTime(): Long {
|
||||||
|
@ -204,12 +228,14 @@ class MedtrumPlugin @Inject constructor(
|
||||||
|
|
||||||
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
|
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
|
||||||
aapsLogger.info(LTag.PUMP, "setTempBasalPercent - percent: $percent, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
|
aapsLogger.info(LTag.PUMP, "setTempBasalPercent - percent: $percent, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
|
||||||
return PumpEnactResult(injector) // TODO
|
return PumpEnactResult(injector).success(false).enacted(false)
|
||||||
|
.comment("Medtrum driver does not support percentage temp basals")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
|
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
|
||||||
aapsLogger.info(LTag.PUMP, "setExtendedBolus - insulin: $insulin, durationInMinutes: $durationInMinutes")
|
aapsLogger.info(LTag.PUMP, "setExtendedBolus - insulin: $insulin, durationInMinutes: $durationInMinutes")
|
||||||
return PumpEnactResult(injector) // TODO
|
return PumpEnactResult(injector).success(false).enacted(false)
|
||||||
|
.comment("Medtrum driver does not support extended boluses")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package info.nightscout.pump.medtrum
|
package info.nightscout.pump.medtrum
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import info.nightscout.interfaces.Constants
|
import info.nightscout.interfaces.Constants
|
||||||
import info.nightscout.interfaces.profile.Instantiator
|
import info.nightscout.interfaces.profile.Instantiator
|
||||||
import info.nightscout.interfaces.profile.Profile
|
import info.nightscout.interfaces.profile.Profile
|
||||||
|
@ -14,6 +16,8 @@ import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import info.nightscout.shared.utils.DateUtil
|
import info.nightscout.shared.utils.DateUtil
|
||||||
import info.nightscout.shared.utils.T
|
import info.nightscout.shared.utils.T
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
@ -26,29 +30,37 @@ class MedtrumPump @Inject constructor(
|
||||||
private val instantiator: Instantiator
|
private val instantiator: Instantiator
|
||||||
) {
|
) {
|
||||||
|
|
||||||
enum class PatchActivationState(val state: Int) {
|
// Pump state flow
|
||||||
NONE(0),
|
// TODO We might want to save this in SP, or at least get activated state from SP
|
||||||
IDLE(1),
|
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
|
||||||
ACTIVATING(2),
|
val pumpStateFlow: StateFlow<MedtrumPumpState> = _pumpState
|
||||||
ACTIVATED(3),
|
|
||||||
DEACTIVATING(4),
|
|
||||||
DEACTIVATED(5),
|
|
||||||
ERROR(6)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pump state and parameters
|
var pumpState: MedtrumPumpState
|
||||||
var pumpState = MedtrumPumpState.NONE // TODO save in SP
|
get() = _pumpState.value
|
||||||
var patchActivationState = PatchActivationState.NONE // TODO save in SP
|
set(value) {
|
||||||
|
_pumpState.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prime progress as state flow
|
||||||
|
private val _primeProgress = MutableStateFlow(0)
|
||||||
|
val primeProgressFlow: StateFlow<Int> = _primeProgress
|
||||||
|
|
||||||
|
var primeProgress: Int
|
||||||
|
get() = _primeProgress.value
|
||||||
|
set(value) {
|
||||||
|
_primeProgress.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Save this in SP? This might be a bit tricky as we only know what we have set, not what the pump has set but the pump should not change it, addtionally we should track the active basal profile in pump e.g. Basal patern A, B etc
|
||||||
|
var actualBasalProfile = byteArrayOf(0)
|
||||||
var patchId = 0L
|
var patchId = 0L
|
||||||
var lastKnownSequenceNumber = 0
|
var lastKnownSequenceNumber = 0
|
||||||
var lastTimeReceivedFromPump = 0L // Time in seconds!
|
var lastTimeReceivedFromPump = 0L // Time in seconds!
|
||||||
var suspendTime = 0L // Time in seconds!
|
var suspendTime = 0L // Time in seconds!
|
||||||
var patchStartTime = 0L // Time in seconds!
|
var patchStartTime = 0L // Time in seconds!
|
||||||
var patchAge = 0L // Time in seconds!
|
var patchAge = 0L // Time in seconds!
|
||||||
|
|
||||||
var reservoir = 0.0
|
var reservoir = 0.0
|
||||||
var primeProgress = 0
|
|
||||||
|
|
||||||
var batteryVoltage_A = 0.0
|
var batteryVoltage_A = 0.0
|
||||||
var batteryVoltage_B = 0.0
|
var batteryVoltage_B = 0.0
|
||||||
|
@ -67,7 +79,6 @@ class MedtrumPump @Inject constructor(
|
||||||
var lastStopSequence = 0
|
var lastStopSequence = 0
|
||||||
var lastStopPatchId = 0
|
var lastStopPatchId = 0
|
||||||
|
|
||||||
|
|
||||||
// TODO set these setting on init
|
// TODO set these setting on init
|
||||||
// User settings (desired values, to be set on pump)
|
// User settings (desired values, to be set on pump)
|
||||||
var desiredPatchExpiration = false
|
var desiredPatchExpiration = false
|
||||||
|
@ -75,7 +86,6 @@ class MedtrumPump @Inject constructor(
|
||||||
var desiredHourlyMaxInsulin: Int = 40
|
var desiredHourlyMaxInsulin: Int = 40
|
||||||
var desiredDailyMaxInsulin: Int = 180
|
var desiredDailyMaxInsulin: Int = 180
|
||||||
|
|
||||||
|
|
||||||
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
|
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
|
||||||
val list = nsProfile.getBasalValues()
|
val list = nsProfile.getBasalValues()
|
||||||
var basals = byteArrayOf()
|
var basals = byteArrayOf()
|
||||||
|
@ -87,7 +97,7 @@ class MedtrumPump @Inject constructor(
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
basals += ((rate shl 12) + time).toByteArray(3)
|
basals += ((rate shl 12) + time).toByteArray(3)
|
||||||
aapsLogger.debug(LTag.PUMP, "buildMedtrumProfileArray: value: ${item.value} time: ${item.timeAsSeconds}")
|
aapsLogger.debug(LTag.PUMP, "buildMedtrumProfileArray: value: ${item.value} time: ${item.timeAsSeconds}, converted: $rate, $time")
|
||||||
}
|
}
|
||||||
return (list.size).toByteArray(1) + basals
|
return (list.size).toByteArray(1) + basals
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,8 @@ enum class PatchStep {
|
||||||
DISCARDED_FROM_ALARM,
|
DISCARDED_FROM_ALARM,
|
||||||
PREPARE_PATCH,
|
PREPARE_PATCH,
|
||||||
PRIME,
|
PRIME,
|
||||||
ATTACH_INSERT_NEEDLE,
|
ATTACH_PATCH,
|
||||||
BASAL_SCHEDULE,
|
ACTIVATE,
|
||||||
CHECK_CONNECTION,
|
|
||||||
CANCEL,
|
CANCEL,
|
||||||
COMPLETE,
|
COMPLETE,
|
||||||
BACK_TO_HOME,
|
BACK_TO_HOME,
|
||||||
|
|
|
@ -3,7 +3,7 @@ package info.nightscout.pump.medtrum.comm.enums
|
||||||
enum class MedtrumPumpState(val state: Byte) {
|
enum class MedtrumPumpState(val state: Byte) {
|
||||||
NONE(0),
|
NONE(0),
|
||||||
IDLE(1),
|
IDLE(1),
|
||||||
FILL(2),
|
FILLED(2),
|
||||||
PRIMING(3),
|
PRIMING(3),
|
||||||
PRIMED(4),
|
PRIMED(4),
|
||||||
EJECTING(5),
|
EJECTING(5),
|
||||||
|
|
|
@ -57,14 +57,23 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
|
||||||
* bytes 15 - end // Basal profile > see MedtrumPump
|
* bytes 15 - end // Basal profile > see MedtrumPump
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
val autoSuspendEnable: Byte = 0
|
||||||
|
val autoSuspendTime: Byte = 12 // Not sure why, but pump needs this in order to activate
|
||||||
|
|
||||||
val patchExpiration: Byte = medtrumPump.desiredPatchExpiration.toByte()
|
val patchExpiration: Byte = medtrumPump.desiredPatchExpiration.toByte()
|
||||||
val alarmSetting: Byte = medtrumPump.desiredAlarmSetting
|
val alarmSetting: Byte = medtrumPump.desiredAlarmSetting
|
||||||
|
|
||||||
|
val lowSuspend: Byte = 0
|
||||||
|
val predictiveLowSuspend: Byte = 0
|
||||||
|
val predictiveLowSuspendRange: Byte = 30 // Not sure why, but pump needs this in order to activate
|
||||||
|
|
||||||
val hourlyMaxInsulin: Int = round(medtrumPump.desiredHourlyMaxInsulin / 0.05).toInt()
|
val hourlyMaxInsulin: Int = round(medtrumPump.desiredHourlyMaxInsulin / 0.05).toInt()
|
||||||
val dailyMaxInsulin: Int = round(medtrumPump.desiredDailyMaxInsulin / 0.05).toInt()
|
val dailyMaxInsulin: Int = round(medtrumPump.desiredDailyMaxInsulin / 0.05).toInt()
|
||||||
val currentTDD: Double = tddCalculator.calculateToday()?.totalAmount?.div(0.05) ?: 0.0
|
val currentTDD: Double = tddCalculator.calculateToday()?.totalAmount?.div(0.05) ?: 0.0
|
||||||
|
|
||||||
return byteArrayOf(opCode) + 0.toByteArray(2) + patchExpiration + alarmSetting + 0.toByteArray(3) + hourlyMaxInsulin.toByteArray(2) + dailyMaxInsulin.toByteArray(2) + currentTDD.toInt()
|
return byteArrayOf(opCode) + autoSuspendEnable + autoSuspendTime + patchExpiration + alarmSetting + lowSuspend + predictiveLowSuspend + predictiveLowSuspendRange + hourlyMaxInsulin.toByteArray(
|
||||||
.toByteArray(2) + 1.toByte() + basalProfile
|
2
|
||||||
|
) + dailyMaxInsulin.toByteArray(2) + currentTDD.toInt().toByteArray(2) + 1.toByte() + basalProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleResponse(data: ByteArray): Boolean {
|
override fun handleResponse(data: ByteArray): Boolean {
|
||||||
|
@ -82,7 +91,9 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
|
||||||
|
|
||||||
medtrumPump.patchId = patchId
|
medtrumPump.patchId = patchId
|
||||||
medtrumPump.lastTimeReceivedFromPump = time
|
medtrumPump.lastTimeReceivedFromPump = time
|
||||||
// TODO: Handle basal here, and report to AAPS directly
|
// Update the actual basal profile
|
||||||
|
medtrumPump.actualBasalProfile = basalProfile
|
||||||
|
// TODO: Handle history entry
|
||||||
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
|
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,13 @@ open class MedtrumPacket(protected var injector: HasAndroidInjector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getRequest(): ByteArray {
|
open fun getRequest(): ByteArray {
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Get REQUEST TEST")
|
|
||||||
return byteArrayOf(opCode)
|
return byteArrayOf(opCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** handles a response from the Medtrum pump, returns true if command was successfull, returns false if command failed or waiting for response */
|
/** handles a response from the Medtrum pump, returns true if command was successfull, returns false if command failed or waiting for response */
|
||||||
open fun handleResponse(data: ByteArray): Boolean {
|
open fun handleResponse(data: ByteArray): Boolean {
|
||||||
if (expectedMinRespLength > data.size) {
|
// Check for broken packets
|
||||||
|
if (RESP_RESULT_END > data.size) {
|
||||||
failed = true
|
failed = true
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected response length, expected: $expectedMinRespLength got: ${data.size}")
|
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected response length, expected: $expectedMinRespLength got: ${data.size}")
|
||||||
return false
|
return false
|
||||||
|
@ -48,11 +48,17 @@ open class MedtrumPacket(protected var injector: HasAndroidInjector) {
|
||||||
return when {
|
return when {
|
||||||
incomingOpCode != opCode -> {
|
incomingOpCode != opCode -> {
|
||||||
failed = true
|
failed = true
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected command, expected: $opCode got: $incomingOpCode")
|
aapsLogger.error(LTag.PUMPCOMM, "handleResponse: Unexpected command, expected: $opCode got: $incomingOpCode")
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
responseCode == 0 -> {
|
responseCode == 0 -> {
|
||||||
|
// Check if length is what is expected from this type of packet
|
||||||
|
if (expectedMinRespLength > data.size) {
|
||||||
|
failed = true
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected response length, expected: $expectedMinRespLength got: ${data.size}")
|
||||||
|
return false
|
||||||
|
}
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Happy command: $opCode response: $responseCode")
|
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Happy command: $opCode response: $responseCode")
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -65,7 +71,7 @@ open class MedtrumPacket(protected var injector: HasAndroidInjector) {
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
failed = true
|
failed = true
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Error in command: $opCode response: $responseCode")
|
aapsLogger.warn(LTag.PUMPCOMM, "handleResponse: Error in command: $opCode response: $responseCode")
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,19 +14,19 @@ import kotlin.experimental.and
|
||||||
|
|
||||||
class NotificationPacket(val injector: HasAndroidInjector) {
|
class NotificationPacket(val injector: HasAndroidInjector) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a bit of a special packet, as it is not a command packet
|
* This is a bit of a special packet, as it is not a command packet
|
||||||
* but a notification packet. It is sent by the pump to the phone
|
* but a notification packet. It is sent by the pump to the phone
|
||||||
* when the pump has a notification to send.
|
* when the pump has a notification to send.
|
||||||
*
|
*
|
||||||
* Notifications are sent regualary, regardless of the pump state.
|
* Notifications are sent regualary, regardless of the pump state.
|
||||||
*
|
*
|
||||||
* There can be multiple messages in one packet, this is noted by the fieldMask.
|
* There can be multiple messages in one packet, this is noted by the fieldMask.
|
||||||
*
|
*
|
||||||
* Byte 1: State (Handle a state change directly? before analyzing further?)
|
* Byte 1: State (Handle a state change directly? before analyzing further?)
|
||||||
* Byte 2-3: FieldMask (BitMask which tells the fields present in the message)
|
* Byte 2-3: FieldMask (BitMask which tells the fields present in the message)
|
||||||
* Byte 4-end : status data
|
* Byte 4-end : status data
|
||||||
*
|
*
|
||||||
* When multiple fields are in the message, the data is concatenated.
|
* When multiple fields are in the message, the data is concatenated.
|
||||||
* This kind of message can also come as a response of SynchronizePacket,
|
* This kind of message can also come as a response of SynchronizePacket,
|
||||||
* and can be handled here by handleMaskedMessage() as well.
|
* and can be handled here by handleMaskedMessage() as well.
|
||||||
|
@ -36,9 +36,10 @@ class NotificationPacket(val injector: HasAndroidInjector) {
|
||||||
@Inject lateinit var medtrumPump: MedtrumPump
|
@Inject lateinit var medtrumPump: MedtrumPump
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val NOTIF_STATE_START = 0
|
private const val NOTIF_STATE_START = 0
|
||||||
private const val NOTIF_STATE_END = NOTIF_STATE_START + 1
|
private const val NOTIF_STATE_END = NOTIF_STATE_START + 1
|
||||||
|
|
||||||
private const val MASK_SUSPEND = 0x01
|
private const val MASK_SUSPEND = 0x01
|
||||||
private const val MASK_NORMAL_BOLUS = 0x02
|
private const val MASK_NORMAL_BOLUS = 0x02
|
||||||
private const val MASK_EXTENDED_BOLUS = 0x04
|
private const val MASK_EXTENDED_BOLUS = 0x04
|
||||||
|
@ -79,7 +80,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
|
||||||
/**
|
/**
|
||||||
* Handle a message with a field mask, can be used by other packets as well
|
* Handle a message with a field mask, can be used by other packets as well
|
||||||
*/
|
*/
|
||||||
fun handleMaskedMessage(data: ByteArray) {
|
fun handleMaskedMessage(data: ByteArray) {
|
||||||
val fieldMask = data.copyOfRange(0, 2).toInt()
|
val fieldMask = data.copyOfRange(0, 2).toInt()
|
||||||
var offset = 2
|
var offset = 2
|
||||||
|
|
||||||
|
@ -96,13 +97,13 @@ class NotificationPacket(val injector: HasAndroidInjector) {
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
|
aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
|
||||||
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
|
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
|
||||||
var bolusType = bolusData and 0x7F
|
var bolusType = bolusData and 0x7F
|
||||||
var bolusCompleted = (bolusData shr 7) and 0x01
|
var bolusCompleted = (bolusData shr 7) and 0x01 // TODO: Check for other flags here :)
|
||||||
var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() / 0.05
|
var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() / 0.05
|
||||||
// TODO Sync bolus flow:
|
// TODO Sync bolus flow:
|
||||||
// If bolus is known add status
|
// If bolus is known add status
|
||||||
// If bolus is not known start read bolus
|
// If bolus is not known start read bolus
|
||||||
// When bolus is completed, remove bolus from medtrumPump
|
// When bolus is completed, remove bolus from medtrumPump
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
|
aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolusData: $bolusData bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
|
||||||
offset += 3
|
offset += 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +173,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
|
||||||
medtrumPump.alarmFlags = data.copyOfRange(offset, offset + 2).toInt()
|
medtrumPump.alarmFlags = data.copyOfRange(offset, offset + 2).toInt()
|
||||||
medtrumPump.alarmParameter = data.copyOfRange(offset + 2, offset + 4).toInt()
|
medtrumPump.alarmParameter = data.copyOfRange(offset + 2, offset + 4).toInt()
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Alarm flags: ${medtrumPump.alarmFlags}, alarm parameter: ${medtrumPump.alarmParameter}")
|
aapsLogger.debug(LTag.PUMPCOMM, "Alarm flags: ${medtrumPump.alarmFlags}, alarm parameter: ${medtrumPump.alarmParameter}")
|
||||||
offset += 4
|
offset += 4
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldMask and MASK_START_TIME != 0) {
|
if (fieldMask and MASK_START_TIME != 0) {
|
||||||
|
@ -202,5 +203,5 @@ class NotificationPacket(val injector: HasAndroidInjector) {
|
||||||
if (fieldMask and MASK_UNUSED_LEGACY != 0) {
|
if (fieldMask and MASK_UNUSED_LEGACY != 0) {
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Unused legacy notification received, not handled!")
|
aapsLogger.debug(LTag.PUMPCOMM, "Unused legacy notification received, not handled!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,56 @@ package info.nightscout.pump.medtrum.comm.packets
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.pump.medtrum.MedtrumPump
|
import info.nightscout.pump.medtrum.MedtrumPump
|
||||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BASAL_PROFILE
|
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BASAL_PROFILE
|
||||||
|
import info.nightscout.pump.medtrum.extension.toInt
|
||||||
|
import info.nightscout.pump.medtrum.extension.toLong
|
||||||
|
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SetBasalProfilePacket(injector: HasAndroidInjector, private val basalProfile: ByteArray) : MedtrumPacket(injector) {
|
class SetBasalProfilePacket(injector: HasAndroidInjector, private val basalProfile: ByteArray) : MedtrumPacket(injector) {
|
||||||
|
|
||||||
@Inject lateinit var medtrumPump: MedtrumPump
|
@Inject lateinit var medtrumPump: MedtrumPump
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val RESP_BASAL_TYPE_START = 6
|
||||||
|
private const val RESP_BASAL_TYPE_END = RESP_BASAL_TYPE_START + 1
|
||||||
|
private const val RESP_BASAL_VALUE_START = 7
|
||||||
|
private const val RESP_BASAL_VALUE_END = RESP_BASAL_VALUE_START + 2
|
||||||
|
private const val RESP_BASAL_SEQUENCE_START = 9
|
||||||
|
private const val RESP_BASAL_SEQUENCE_END = RESP_BASAL_SEQUENCE_START + 2
|
||||||
|
private const val RESP_BASAL_PATCH_ID_START = 11
|
||||||
|
private const val RESP_BASAL_PATCH_ID_END = RESP_BASAL_PATCH_ID_START + 2
|
||||||
|
private const val RESP_BASAL_START_TIME_START = 13
|
||||||
|
private const val RESP_BASAL_START_TIME_END = RESP_BASAL_START_TIME_START + 4
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
opCode = SET_BASAL_PROFILE.code
|
opCode = SET_BASAL_PROFILE.code
|
||||||
|
expectedMinRespLength = RESP_BASAL_START_TIME_END
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRequest(): ByteArray {
|
override fun getRequest(): ByteArray {
|
||||||
val basalType: Byte = 1 // Fixed to normal basal
|
val basalType: Byte = 1 // Fixed to normal basal
|
||||||
return byteArrayOf(opCode) + basalType + basalProfile
|
return byteArrayOf(opCode) + basalType + basalProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handleResponse(data: ByteArray): Boolean {
|
||||||
|
val success = super.handleResponse(data)
|
||||||
|
if (success) {
|
||||||
|
val medtrumTimeUtil = MedtrumTimeUtil()
|
||||||
|
val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
|
||||||
|
val basalValue = data.copyOfRange(RESP_BASAL_VALUE_START, RESP_BASAL_VALUE_END).toInt() * 0.05
|
||||||
|
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
|
||||||
|
val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
|
||||||
|
val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
|
||||||
|
|
||||||
|
// Update the actual basal profile
|
||||||
|
medtrumPump.actualBasalProfile = basalProfile
|
||||||
|
// TODO: Do we need to let AAPS know? Maybe depends on where we cancel TBR if we need to
|
||||||
|
// TODO: Handle history entry
|
||||||
|
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime)
|
||||||
|
}
|
||||||
|
return success
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
|
||||||
var state = MedtrumPumpState.fromByte(data[RESP_STATE_START])
|
var state = MedtrumPumpState.fromByte(data[RESP_STATE_START])
|
||||||
|
|
||||||
medtrumPump.pumpState = state
|
medtrumPump.pumpState = state
|
||||||
|
|
||||||
var fieldMask = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
|
var fieldMask = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
|
||||||
var syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)
|
var syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)
|
||||||
var offset = 0
|
var offset = 0
|
||||||
|
@ -46,8 +46,7 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: fieldMask: $fieldMask")
|
aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: fieldMask: $fieldMask")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove bolus fields from fieldMask if fields are present
|
// Remove bolus fields from fieldMask if fields are present (we sync bolus trough other commands)
|
||||||
// TODO: Test if this workaround is needed (hence the warning log)
|
|
||||||
if (fieldMask and MASK_SUSPEND != 0) {
|
if (fieldMask and MASK_SUSPEND != 0) {
|
||||||
offset += 4 // If field is present, skip 4 bytes
|
offset += 4 // If field is present, skip 4 bytes
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import dagger.multibindings.IntoMap
|
import dagger.multibindings.IntoMap
|
||||||
|
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumActivateFragment
|
||||||
|
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
|
||||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
|
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
|
||||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
|
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
|
||||||
import info.nightscout.pump.medtrum.services.MedtrumService
|
import info.nightscout.pump.medtrum.services.MedtrumService
|
||||||
|
@ -56,6 +58,14 @@ abstract class MedtrumModule {
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
internal abstract fun contributesPrimeFragment(): MedtrumPrimeFragment
|
internal abstract fun contributesPrimeFragment(): MedtrumPrimeFragment
|
||||||
|
|
||||||
|
@FragmentScope
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
internal abstract fun contributesAttachPatchFragment(): MedtrumAttachPatchFragment
|
||||||
|
|
||||||
|
@FragmentScope
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
internal abstract fun contributesActivateFragment(): MedtrumActivateFragment
|
||||||
|
|
||||||
// ACTIVITIES
|
// ACTIVITIES
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun contributesMedtrumActivity(): MedtrumActivity
|
abstract fun contributesMedtrumActivity(): MedtrumActivity
|
||||||
|
@ -63,4 +73,5 @@ abstract class MedtrumModule {
|
||||||
// SERVICE
|
// SERVICE
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun contributesMedtrumService(): MedtrumService
|
abstract fun contributesMedtrumService(): MedtrumService
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import info.nightscout.shared.utils.DateUtil
|
import info.nightscout.shared.utils.DateUtil
|
||||||
|
import info.nightscout.shared.utils.T
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -75,29 +76,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
// TODO: Stuff like this in a settings class?
|
// TODO: Stuff like this in a settings class?
|
||||||
private var mLastDeviceTime: Long = 0
|
private var mLastDeviceTime: Long = 0
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private val MASK_SUSPEND = 0x01
|
|
||||||
private val MASK_NORMAL_BOLUS = 0x02
|
|
||||||
private val MASK_EXTENDED_BOLUS = 0x04
|
|
||||||
private val MASK_BASAL = 0x08
|
|
||||||
|
|
||||||
private val MASK_SETUP = 0x10
|
|
||||||
private val MASK_RESERVOIR = 0x20
|
|
||||||
private val MASK_LIFE_TIME = 0x40
|
|
||||||
private val MASK_BATTERY = 0x80
|
|
||||||
|
|
||||||
private val MASK_STORAGE = 0x100
|
|
||||||
private val MASK_ALARM = 0x200
|
|
||||||
private val MASK_START_TIME = 0x400
|
|
||||||
private val MASK_UNKNOWN_1 = 0x800
|
|
||||||
|
|
||||||
private val MASK_UNUSED_CGM = 0x1000
|
|
||||||
private val MASK_UNUSED_COMMAND_CONFIRM = 0x2000
|
|
||||||
private val MASK_UNUSED_AUTO_STATUS = 0x4000
|
|
||||||
private val MASK_UNUSED_LEGACY = 0x8000
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
bleComm.setCallback(this)
|
bleComm.setCallback(this)
|
||||||
|
@ -135,6 +113,18 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startPrime(): Boolean {
|
||||||
|
val packet = PrimePacket(injector)
|
||||||
|
return sendPacketAndGetResponse(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startActivate(): Boolean {
|
||||||
|
// TODO not sure this is the correct way lol, We might need to tell AAPS which profile is active
|
||||||
|
val profile = profileFunction.getProfile()?.let { medtrumPump.buildMedtrumProfileArray(it) }
|
||||||
|
val packet = profile?.let { ActivatePacket(injector, it) }
|
||||||
|
return packet?.let { sendPacketAndGetResponse(it) } == true
|
||||||
|
}
|
||||||
|
|
||||||
fun stopConnecting() {
|
fun stopConnecting() {
|
||||||
// TODO proper way for this might need send commands etc
|
// TODO proper way for this might need send commands etc
|
||||||
bleComm.stopConnecting()
|
bleComm.stopConnecting()
|
||||||
|
@ -177,9 +167,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateBasalsInPump(profile: Profile): Boolean {
|
fun updateBasalsInPump(profile: Profile): Boolean {
|
||||||
if (!isConnected) return false
|
val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
|
||||||
// TODO
|
return packet?.let { sendPacketAndGetResponse(it) } == true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changePump() {
|
fun changePump() {
|
||||||
|
@ -189,11 +178,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
|
aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
|
||||||
}
|
}
|
||||||
// TODO: What do we do with active patch here?
|
// TODO: What do we do with active patch here? Getting status should be enough?
|
||||||
when (currentState) {
|
when (currentState) {
|
||||||
// is IdleState -> connect("changePump")
|
is IdleState -> connect("changePump")
|
||||||
// is ReadyState -> disconnect("changePump")
|
// is ReadyState -> disconnect("changePump")
|
||||||
else -> null // TODO: What to do here? Abort stuff?
|
else -> null // TODO: What to do here? Abort stuff?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,6 +233,19 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
currentState.onEnter()
|
currentState.onEnter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun sendPacketAndGetResponse(packet: MedtrumPacket): Boolean {
|
||||||
|
var result = false
|
||||||
|
if (currentState is ReadyState) {
|
||||||
|
toState(CommandState())
|
||||||
|
mPacket = packet
|
||||||
|
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
|
||||||
|
result = currentState.waitForResponse()
|
||||||
|
} else {
|
||||||
|
aapsLogger.error(LTag.PUMPCOMM, "Send packet attempt when in non Ready state")
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// State class, Can we move this to different file?
|
// State class, Can we move this to different file?
|
||||||
private abstract inner class State {
|
private abstract inner class State {
|
||||||
|
|
||||||
|
@ -265,11 +267,18 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
// TODO: Check flow for this
|
// TODO: Check flow for this
|
||||||
toState(IdleState())
|
toState(IdleState())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun waitForResponse(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class IdleState : State() {
|
private inner class IdleState : State() {
|
||||||
|
|
||||||
override fun onEnter() {}
|
override fun onEnter() {
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached IdleState")
|
||||||
|
connect("IdleState onEnter")
|
||||||
|
}
|
||||||
|
|
||||||
override fun onConnected() {
|
override fun onConnected() {
|
||||||
super.onConnected()
|
super.onConnected()
|
||||||
|
@ -278,10 +287,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
|
|
||||||
override fun onDisconnected() {
|
override fun onDisconnected() {
|
||||||
super.onDisconnected()
|
super.onDisconnected()
|
||||||
// TODO replace this by proper connecting state where we can retry
|
connect("IdleState onDisconnected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State for connect flow, could be replaced by commandState and steps in connect()
|
||||||
private inner class AuthState : State() {
|
private inner class AuthState : State() {
|
||||||
|
|
||||||
override fun onEnter() {
|
override fun onEnter() {
|
||||||
|
@ -306,6 +316,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State for connect flow, could be replaced by commandState and steps in connect()
|
||||||
private inner class GetDeviceTypeState : State() {
|
private inner class GetDeviceTypeState : State() {
|
||||||
|
|
||||||
override fun onEnter() {
|
override fun onEnter() {
|
||||||
|
@ -330,6 +341,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State for connect flow, could be replaced by commandState and steps in connect()
|
||||||
private inner class GetTimeState : State() {
|
private inner class GetTimeState : State() {
|
||||||
|
|
||||||
override fun onEnter() {
|
override fun onEnter() {
|
||||||
|
@ -361,6 +373,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State for connect flow, could be replaced by commandState and steps in connect()
|
||||||
private inner class SetTimeState : State() {
|
private inner class SetTimeState : State() {
|
||||||
|
|
||||||
override fun onEnter() {
|
override fun onEnter() {
|
||||||
|
@ -381,6 +394,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State for connect flow, could be replaced by commandState and steps in connect()
|
||||||
private inner class SetTimeZoneState : State() {
|
private inner class SetTimeZoneState : State() {
|
||||||
|
|
||||||
override fun onEnter() {
|
override fun onEnter() {
|
||||||
|
@ -401,6 +415,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State for connect flow, could be replaced by commandState and steps in connect()
|
||||||
private inner class SynchronizeState : State() {
|
private inner class SynchronizeState : State() {
|
||||||
|
|
||||||
override fun onEnter() {
|
override fun onEnter() {
|
||||||
|
@ -422,6 +437,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State for connect flow, could be replaced by commandState and steps in connect()
|
||||||
private inner class SubscribeState : State() {
|
private inner class SubscribeState : State() {
|
||||||
|
|
||||||
override fun onEnter() {
|
override fun onEnter() {
|
||||||
|
@ -442,6 +458,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This state is reached when the patch is ready to receive commands (Activation, Bolus, temp basal and whatever)
|
||||||
private inner class ReadyState : State() {
|
private inner class ReadyState : State() {
|
||||||
|
|
||||||
override fun onEnter() {
|
override fun onEnter() {
|
||||||
|
@ -451,6 +468,53 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
isConnected = true
|
isConnected = true
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
|
||||||
}
|
}
|
||||||
// Just a placeholder, this state is reached when the patch is ready to receive commands (Bolus, temp basal and whatever)
|
}
|
||||||
|
|
||||||
|
// This state is when a command is send and we wait for a response for that command
|
||||||
|
private inner class CommandState : State() {
|
||||||
|
|
||||||
|
private var responseHandled = false
|
||||||
|
private var responseSuccess = false
|
||||||
|
|
||||||
|
override fun onEnter() {
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached CommandState")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onIndication(data: ByteArray) {
|
||||||
|
if (mPacket?.handleResponse(data) == true) {
|
||||||
|
// Succes!
|
||||||
|
responseHandled = true
|
||||||
|
responseSuccess = true
|
||||||
|
toState(ReadyState())
|
||||||
|
} else if (mPacket?.failed == true) {
|
||||||
|
// Failure
|
||||||
|
responseHandled = true
|
||||||
|
responseSuccess = false
|
||||||
|
toState(ReadyState())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisconnected() {
|
||||||
|
super.onDisconnected()
|
||||||
|
responseHandled = true
|
||||||
|
responseSuccess = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun waitForResponse(): Boolean {
|
||||||
|
val startTime = System.currentTimeMillis()
|
||||||
|
val timeoutMillis = T.secs(45).msecs()
|
||||||
|
while (!responseHandled) {
|
||||||
|
if (System.currentTimeMillis() - startTime > timeoutMillis) {
|
||||||
|
// If we haven't received a response in the specified time, assume the command failed
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service CommandState timeout")
|
||||||
|
// Disconnect to cancel any outstanding commands and go back to ready state
|
||||||
|
bleComm.disconnect("Timeout")
|
||||||
|
toState(ReadyState())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
Thread.sleep(100)
|
||||||
|
}
|
||||||
|
return responseSuccess
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.eopatch.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import info.nightscout.core.ui.toast.ToastUtils
|
||||||
|
import info.nightscout.pump.medtrum.R
|
||||||
|
import info.nightscout.pump.medtrum.code.PatchStep
|
||||||
|
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumActivateBinding
|
||||||
|
import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
|
||||||
|
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
|
||||||
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.rx.logging.LTag
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MedtrumActivateFragment : MedtrumBaseFragment<FragmentMedtrumActivateBinding>() {
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance(): MedtrumActivateFragment = MedtrumActivateFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLayoutId(): Int = R.layout.fragment_medtrum_activate
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding.apply {
|
||||||
|
viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
|
||||||
|
viewModel?.apply {
|
||||||
|
setupStep.observe(viewLifecycleOwner) {
|
||||||
|
when (it) {
|
||||||
|
MedtrumViewModel.SetupStep.PRIMED -> Unit // Nothing to do here, previous state
|
||||||
|
MedtrumViewModel.SetupStep.ACTIVATED -> btnPositive.visibility = View.VISIBLE
|
||||||
|
MedtrumViewModel.SetupStep.ERROR -> {
|
||||||
|
ToastUtils.errorToast(requireContext(), "Error Activating") // TODO: String resource and show error message
|
||||||
|
moveStep(PatchStep.CANCEL)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
|
||||||
|
moveStep(PatchStep.CANCEL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startActivate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ import android.os.Bundle
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumActivateFragment
|
||||||
|
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
|
||||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
|
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
|
||||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
|
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
|
||||||
import info.nightscout.core.utils.extensions.safeGetSerializableExtra
|
import info.nightscout.core.utils.extensions.safeGetSerializableExtra
|
||||||
|
@ -42,6 +44,9 @@ class MedtrumActivity : MedtrumBaseActivity<ActivityMedtrumBinding>() {
|
||||||
when (it) {
|
when (it) {
|
||||||
PatchStep.PREPARE_PATCH -> setupViewFragment(MedtrumPreparePatchFragment.newInstance())
|
PatchStep.PREPARE_PATCH -> setupViewFragment(MedtrumPreparePatchFragment.newInstance())
|
||||||
PatchStep.PRIME -> setupViewFragment(MedtrumPrimeFragment.newInstance())
|
PatchStep.PRIME -> setupViewFragment(MedtrumPrimeFragment.newInstance())
|
||||||
|
PatchStep.ATTACH_PATCH -> setupViewFragment(MedtrumAttachPatchFragment.newInstance())
|
||||||
|
PatchStep.ACTIVATE -> setupViewFragment(MedtrumActivateFragment.newInstance())
|
||||||
|
PatchStep.COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
|
||||||
PatchStep.CANCEL -> this@MedtrumActivity.finish()
|
PatchStep.CANCEL -> this@MedtrumActivity.finish()
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.eopatch.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import info.nightscout.core.ui.toast.ToastUtils
|
||||||
|
import info.nightscout.pump.medtrum.R
|
||||||
|
import info.nightscout.pump.medtrum.code.PatchStep
|
||||||
|
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumAttachPatchBinding
|
||||||
|
import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
|
||||||
|
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
|
||||||
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.rx.logging.LTag
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MedtrumAttachPatchFragment : MedtrumBaseFragment<FragmentMedtrumAttachPatchBinding>() {
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance(): MedtrumAttachPatchFragment = MedtrumAttachPatchFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLayoutId(): Int = R.layout.fragment_medtrum_attach_patch
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
aapsLogger.debug(LTag.PUMP, "MedtrumAttachPatchFragment onViewCreated")
|
||||||
|
binding.apply {
|
||||||
|
viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
|
||||||
|
viewModel?.apply {
|
||||||
|
setupStep.observe(viewLifecycleOwner) {
|
||||||
|
when (it) {
|
||||||
|
MedtrumViewModel.SetupStep.PRIMED -> Unit // Nothing to do here, previous state
|
||||||
|
MedtrumViewModel.SetupStep.ERROR -> {
|
||||||
|
ToastUtils.errorToast(requireContext(), "Error attach patch") // TODO: String resource and show error message
|
||||||
|
moveStep(PatchStep.CANCEL)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
|
||||||
|
moveStep(PatchStep.CANCEL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import android.view.View
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import info.nightscout.pump.medtrum.MedtrumPump
|
||||||
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumOverviewBinding
|
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumOverviewBinding
|
||||||
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
|
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
|
||||||
import info.nightscout.pump.medtrum.R
|
import info.nightscout.pump.medtrum.R
|
||||||
|
@ -13,6 +14,7 @@ import info.nightscout.pump.medtrum.code.EventType
|
||||||
import info.nightscout.pump.medtrum.code.PatchStep
|
import info.nightscout.pump.medtrum.code.PatchStep
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.rx.logging.LTag
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ class MedtrumOverviewFragment : MedtrumBaseFragment<FragmentMedtrumOverviewBindi
|
||||||
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var medtrumPump: MedtrumPump
|
||||||
private lateinit var resultLauncherForResume: ActivityResultLauncher<Intent>
|
private lateinit var resultLauncherForResume: ActivityResultLauncher<Intent>
|
||||||
private lateinit var resultLauncherForPause: ActivityResultLauncher<Intent>
|
private lateinit var resultLauncherForPause: ActivityResultLauncher<Intent>
|
||||||
|
|
||||||
|
@ -40,7 +43,12 @@ class MedtrumOverviewFragment : MedtrumBaseFragment<FragmentMedtrumOverviewBindi
|
||||||
viewmodel?.apply {
|
viewmodel?.apply {
|
||||||
eventHandler.observe(viewLifecycleOwner) { evt ->
|
eventHandler.observe(viewLifecycleOwner) { evt ->
|
||||||
when (evt.peekContent()) {
|
when (evt.peekContent()) {
|
||||||
EventType.ACTIVATION_CLICKED -> requireContext().apply { startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.PREPARE_PATCH)) }
|
EventType.ACTIVATION_CLICKED -> requireContext().apply {
|
||||||
|
val step = convertToPatchStep(medtrumPump.pumpState)
|
||||||
|
if (step != PatchStep.PREPARE_PATCH) {
|
||||||
|
aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step")
|
||||||
|
}
|
||||||
|
startActivity(MedtrumActivity.createIntentFromMenu(this, step)) }
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@ package info.nightscout.androidaps.plugins.pump.eopatch.ui
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import info.nightscout.core.ui.toast.ToastUtils
|
||||||
import info.nightscout.pump.medtrum.R
|
import info.nightscout.pump.medtrum.R
|
||||||
|
import info.nightscout.pump.medtrum.code.PatchStep
|
||||||
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPreparePatchBinding
|
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPreparePatchBinding
|
||||||
import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
|
import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
|
||||||
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
|
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
|
||||||
|
@ -30,9 +32,19 @@ class MedtrumPreparePatchFragment : MedtrumBaseFragment<FragmentMedtrumPreparePa
|
||||||
viewModel?.apply {
|
viewModel?.apply {
|
||||||
setupStep.observe(viewLifecycleOwner) {
|
setupStep.observe(viewLifecycleOwner) {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
MedtrumViewModel.SetupStep.INITIAL -> btnPositive.visibility = View.GONE
|
||||||
// TODO: Confirmation dialog
|
// TODO: Confirmation dialog
|
||||||
MedtrumViewModel.SetupStep.CONNECTED -> btnPositive.visibility = View.VISIBLE
|
MedtrumViewModel.SetupStep.FILLED -> btnPositive.visibility = View.VISIBLE
|
||||||
else -> Unit
|
|
||||||
|
MedtrumViewModel.SetupStep.ERROR -> {
|
||||||
|
ToastUtils.errorToast(requireContext(), "Error preparing patch") // TODO: String resource and show error message
|
||||||
|
moveStep(PatchStep.CANCEL)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
|
||||||
|
moveStep(PatchStep.CANCEL)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
preparePatch()
|
preparePatch()
|
||||||
|
|
|
@ -3,7 +3,9 @@ package info.nightscout.androidaps.plugins.pump.eopatch.ui
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import info.nightscout.core.ui.toast.ToastUtils
|
||||||
import info.nightscout.pump.medtrum.R
|
import info.nightscout.pump.medtrum.R
|
||||||
|
import info.nightscout.pump.medtrum.code.PatchStep
|
||||||
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPrimeBinding
|
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPrimeBinding
|
||||||
import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
|
import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
|
||||||
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
|
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
|
||||||
|
@ -26,7 +28,24 @@ class MedtrumPrimeFragment : MedtrumBaseFragment<FragmentMedtrumPrimeBinding>()
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding.apply {
|
binding.apply {
|
||||||
viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
|
viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
|
||||||
// TODO do stuff
|
viewModel?.apply {
|
||||||
|
setupStep.observe(viewLifecycleOwner) {
|
||||||
|
when (it) {
|
||||||
|
MedtrumViewModel.SetupStep.FILLED -> Unit // Nothing to do here, previous state
|
||||||
|
MedtrumViewModel.SetupStep.PRIMED -> btnPositive.visibility = View.VISIBLE
|
||||||
|
MedtrumViewModel.SetupStep.ERROR -> {
|
||||||
|
ToastUtils.errorToast(requireContext(), "Error priming") // TODO: String resource and show error message
|
||||||
|
moveStep(PatchStep.CANCEL)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
|
||||||
|
moveStep(PatchStep.CANCEL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startPrime()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package info.nightscout.pump.medtrum.ui.viewmodel
|
package info.nightscout.pump.medtrum.ui.viewmodel
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import info.nightscout.pump.medtrum.code.PatchStep
|
||||||
|
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||||
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
|
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.disposables.Disposable
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
|
@ -28,4 +30,12 @@ abstract class BaseViewModel<N : MedtrumBaseNavigator> : ViewModel() {
|
||||||
|
|
||||||
fun Disposable.addTo() = apply { compositeDisposable.add(this) }
|
fun Disposable.addTo() = apply { compositeDisposable.add(this) }
|
||||||
|
|
||||||
|
fun convertToPatchStep(pumpState: MedtrumPumpState) = when (pumpState) {
|
||||||
|
MedtrumPumpState.NONE, MedtrumPumpState.IDLE -> PatchStep.PREPARE_PATCH
|
||||||
|
MedtrumPumpState.FILLED -> PatchStep.PREPARE_PATCH
|
||||||
|
MedtrumPumpState.PRIMING -> PatchStep.PRIME
|
||||||
|
MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> PatchStep.ATTACH_PATCH
|
||||||
|
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> PatchStep.COMPLETE
|
||||||
|
else -> PatchStep.CANCEL
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -9,6 +9,8 @@ import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
|
||||||
import info.nightscout.pump.medtrum.ui.event.UIEvent
|
import info.nightscout.pump.medtrum.ui.event.UIEvent
|
||||||
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
|
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
|
||||||
import info.nightscout.interfaces.profile.ProfileFunction
|
import info.nightscout.interfaces.profile.ProfileFunction
|
||||||
|
import info.nightscout.pump.medtrum.MedtrumPump
|
||||||
|
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventPumpStatusChanged
|
import info.nightscout.rx.events.EventPumpStatusChanged
|
||||||
|
@ -16,6 +18,9 @@ import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MedtrumOverviewViewModel @Inject constructor(
|
class MedtrumOverviewViewModel @Inject constructor(
|
||||||
|
@ -24,9 +29,11 @@ class MedtrumOverviewViewModel @Inject constructor(
|
||||||
private val aapsSchedulers: AapsSchedulers,
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
private val fabricPrivacy: FabricPrivacy,
|
private val fabricPrivacy: FabricPrivacy,
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
|
private val medtrumPump: MedtrumPump
|
||||||
) : BaseViewModel<MedtrumBaseNavigator>() {
|
) : BaseViewModel<MedtrumBaseNavigator>() {
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
|
private val scope = CoroutineScope(Dispatchers.Default)
|
||||||
|
|
||||||
private val _eventHandler = SingleLiveEvent<UIEvent<EventType>>()
|
private val _eventHandler = SingleLiveEvent<UIEvent<EventType>>()
|
||||||
val eventHandler: LiveData<UIEvent<EventType>>
|
val eventHandler: LiveData<UIEvent<EventType>>
|
||||||
|
@ -36,11 +43,12 @@ class MedtrumOverviewViewModel @Inject constructor(
|
||||||
val bleStatus: LiveData<String>
|
val bleStatus: LiveData<String>
|
||||||
get() = _bleStatus
|
get() = _bleStatus
|
||||||
|
|
||||||
// TODO make these livedata
|
private val _isPatchActivated = SingleLiveEvent<Boolean>()
|
||||||
val isPatchActivated: Boolean
|
val isPatchActivated: LiveData<Boolean>
|
||||||
get() = false // TODO
|
get() = _isPatchActivated
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
// TODO proper connection state from medtrumPump
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventPumpStatusChanged::class.java)
|
.toObservable(EventPumpStatusChanged::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
|
@ -59,6 +67,16 @@ class MedtrumOverviewViewModel @Inject constructor(
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}, fabricPrivacy::logException)
|
}, fabricPrivacy::logException)
|
||||||
|
scope.launch {
|
||||||
|
medtrumPump.pumpStateFlow.collect { state ->
|
||||||
|
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
|
||||||
|
if (state > MedtrumPumpState.EJECTED) {
|
||||||
|
_isPatchActivated.postValue(true)
|
||||||
|
} else {
|
||||||
|
_isPatchActivated.postValue(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClickActivation() {
|
fun onClickActivation() {
|
||||||
|
|
|
@ -4,9 +4,12 @@ import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||||
import info.nightscout.pump.medtrum.MedtrumPlugin
|
import info.nightscout.pump.medtrum.MedtrumPlugin
|
||||||
|
import info.nightscout.pump.medtrum.MedtrumPump
|
||||||
|
import info.nightscout.pump.medtrum.R
|
||||||
import info.nightscout.pump.medtrum.services.MedtrumService
|
import info.nightscout.pump.medtrum.services.MedtrumService
|
||||||
import info.nightscout.pump.medtrum.code.EventType
|
import info.nightscout.pump.medtrum.code.EventType
|
||||||
import info.nightscout.pump.medtrum.code.PatchStep
|
import info.nightscout.pump.medtrum.code.PatchStep
|
||||||
|
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||||
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
|
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
|
||||||
import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
|
import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
|
||||||
import info.nightscout.pump.medtrum.ui.event.UIEvent
|
import info.nightscout.pump.medtrum.ui.event.UIEvent
|
||||||
|
@ -17,8 +20,9 @@ import info.nightscout.rx.events.EventPumpStatusChanged
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MedtrumViewModel @Inject constructor(
|
class MedtrumViewModel @Inject constructor(
|
||||||
|
@ -28,17 +32,20 @@ class MedtrumViewModel @Inject constructor(
|
||||||
private val aapsSchedulers: AapsSchedulers,
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
private val fabricPrivacy: FabricPrivacy,
|
private val fabricPrivacy: FabricPrivacy,
|
||||||
private val medtrumPlugin: MedtrumPlugin,
|
private val medtrumPlugin: MedtrumPlugin,
|
||||||
|
private val medtrumPump: MedtrumPump,
|
||||||
private val sp: SP
|
private val sp: SP
|
||||||
) : BaseViewModel<MedtrumBaseNavigator>() {
|
) : BaseViewModel<MedtrumBaseNavigator>() {
|
||||||
|
|
||||||
val patchStep = MutableLiveData<PatchStep>()
|
val patchStep = MutableLiveData<PatchStep>()
|
||||||
|
|
||||||
val title = "Activation"
|
|
||||||
|
|
||||||
val medtrumService: MedtrumService?
|
val medtrumService: MedtrumService?
|
||||||
get() = medtrumPlugin.getService()
|
get() = medtrumPlugin.getService()
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private val scope = CoroutineScope(Dispatchers.Default)
|
||||||
|
|
||||||
|
private val _title = MutableLiveData<Int>(R.string.step_prepare_patch)
|
||||||
|
val title: LiveData<Int>
|
||||||
|
get() = _title
|
||||||
|
|
||||||
private val _eventHandler = SingleLiveEvent<UIEvent<EventType>>()
|
private val _eventHandler = SingleLiveEvent<UIEvent<EventType>>()
|
||||||
val eventHandler: LiveData<UIEvent<EventType>>
|
val eventHandler: LiveData<UIEvent<EventType>>
|
||||||
|
@ -47,22 +54,37 @@ class MedtrumViewModel @Inject constructor(
|
||||||
private var mInitPatchStep: PatchStep? = null
|
private var mInitPatchStep: PatchStep? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
disposable += rxBus
|
scope.launch {
|
||||||
.toObservable(EventPumpStatusChanged::class.java)
|
medtrumPump.pumpStateFlow.collect { state ->
|
||||||
.observeOn(aapsSchedulers.main)
|
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
|
||||||
.subscribe({
|
when (state) {
|
||||||
when (it.status) {
|
MedtrumPumpState.NONE, MedtrumPumpState.IDLE -> {
|
||||||
EventPumpStatusChanged.Status.CONNECTING -> {}
|
setupStep.postValue(SetupStep.INITIAL)
|
||||||
|
}
|
||||||
|
|
||||||
EventPumpStatusChanged.Status.CONNECTED
|
MedtrumPumpState.FILLED -> {
|
||||||
-> if (patchStep.value == PatchStep.PREPARE_PATCH) setupStep.postValue(SetupStep.CONNECTED) else {
|
setupStep.postValue(SetupStep.FILLED)
|
||||||
}
|
}
|
||||||
|
|
||||||
EventPumpStatusChanged.Status.DISCONNECTED -> {}
|
MedtrumPumpState.PRIMING -> {
|
||||||
|
// setupStep.postValue(SetupStep.PRIMING)
|
||||||
|
// TODO: What to do here? start prime counter?
|
||||||
|
}
|
||||||
|
|
||||||
else -> {}
|
MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> {
|
||||||
}
|
setupStep.postValue(SetupStep.PRIMED)
|
||||||
}, fabricPrivacy::logException)
|
}
|
||||||
|
|
||||||
|
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
|
||||||
|
setupStep.postValue(SetupStep.ACTIVATED)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
setupStep.postValue(SetupStep.ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun moveStep(newPatchStep: PatchStep) {
|
fun moveStep(newPatchStep: PatchStep) {
|
||||||
|
@ -71,8 +93,8 @@ class MedtrumViewModel @Inject constructor(
|
||||||
if (oldPatchStep != newPatchStep) {
|
if (oldPatchStep != newPatchStep) {
|
||||||
when (newPatchStep) {
|
when (newPatchStep) {
|
||||||
PatchStep.CANCEL -> {
|
PatchStep.CANCEL -> {
|
||||||
if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Cancel") else {
|
// if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Cancel") else {
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
|
@ -91,20 +113,49 @@ class MedtrumViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun preparePatch() {
|
fun preparePatch() {
|
||||||
// TODO: Decide if we want to connect already when user is still filling, or if we want to wait after user is done filling
|
// TODO When we dont need to connect what needs to be done here?
|
||||||
medtrumService?.connect("PreparePatch")
|
medtrumService?.connect("PreparePatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startPrime() {
|
||||||
|
// TODO: Get result from service
|
||||||
|
if (medtrumPump.pumpState == MedtrumPumpState.PRIMING) {
|
||||||
|
aapsLogger.info(LTag.PUMP, "startPrime: already priming!")
|
||||||
|
} else {
|
||||||
|
if (medtrumService?.startPrime() == true) {
|
||||||
|
aapsLogger.info(LTag.PUMP, "startPrime: success!")
|
||||||
|
} else {
|
||||||
|
aapsLogger.info(LTag.PUMP, "startPrime: failure!")
|
||||||
|
setupStep.postValue(SetupStep.ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startActivate() {
|
||||||
|
if (medtrumService?.startActivate() == true) {
|
||||||
|
aapsLogger.info(LTag.PUMP, "startActivate: success!")
|
||||||
|
} else {
|
||||||
|
aapsLogger.info(LTag.PUMP, "startActivate: failure!")
|
||||||
|
setupStep.postValue(SetupStep.ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun prepareStep(step: PatchStep?): PatchStep {
|
private fun prepareStep(step: PatchStep?): PatchStep {
|
||||||
// TODO Title per screen :) And proper sync with patchstate
|
// TODO Title per screen :) And proper sync with patchstate
|
||||||
// (step ?: convertToPatchStep(patchConfig.lifecycleEvent.lifeCycle)).let { newStep ->
|
(step ?: convertToPatchStep(medtrumPump.pumpState)).let { newStep ->
|
||||||
|
|
||||||
(step ?: PatchStep.SAFE_DEACTIVATION).let { newStep ->
|
|
||||||
when (newStep) {
|
when (newStep) {
|
||||||
|
PatchStep.PREPARE_PATCH -> R.string.step_prepare_patch
|
||||||
else -> ""
|
PatchStep.PRIME -> R.string.step_prime
|
||||||
|
PatchStep.ATTACH_PATCH -> R.string.step_attach
|
||||||
|
PatchStep.ACTIVATE -> R.string.step_activate
|
||||||
|
PatchStep.COMPLETE -> R.string.step_complete
|
||||||
|
else -> _title.value
|
||||||
}.let {
|
}.let {
|
||||||
|
aapsLogger.info(LTag.PUMP, "prepareStep: title before cond: $it")
|
||||||
|
if (_title.value != it) {
|
||||||
|
aapsLogger.info(LTag.PUMP, "prepareStep: title: $it")
|
||||||
|
_title.postValue(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
patchStep.postValue(newStep)
|
patchStep.postValue(newStep)
|
||||||
|
@ -114,9 +165,11 @@ class MedtrumViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SetupStep {
|
enum class SetupStep {
|
||||||
CONNECTED,
|
INITIAL,
|
||||||
PRIME_READY,
|
FILLED,
|
||||||
ACTIVATED
|
PRIMED,
|
||||||
|
ACTIVATED,
|
||||||
|
ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
val setupStep = MutableLiveData<SetupStep>()
|
val setupStep = MutableLiveData<SetupStep>()
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<import type="info.nightscout.pump.medtrum.code.PatchStep" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
|
android:fillViewport="true"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:context=".ui.MedtrumActivity">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_button"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_negative"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/cancel"
|
||||||
|
android:text="@string/cancel"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/btn_positive"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:onSafeClick="@{() -> viewModel.moveStep(PatchStep.CANCEL)}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_positive"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:contentDescription="@string/string_start_complete"
|
||||||
|
android:text="@string/string_start_complete"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/btn_negative"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:onSafeClick="@{() -> viewModel.moveStep(PatchStep.COMPLETE)}"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</layout>
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<import type="info.nightscout.pump.medtrum.code.PatchStep" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
|
android:fillViewport="true"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:context=".ui.MedtrumActivity">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_button"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_negative"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/cancel"
|
||||||
|
android:text="@string/cancel"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/btn_positive"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:onSafeClick="@{() -> viewModel.moveStep(PatchStep.CANCEL)}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_positive"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:contentDescription="@string/string_start_activate"
|
||||||
|
android:text="@string/string_start_activate"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/btn_negative"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:onSafeClick="@{() -> viewModel.moveStep(PatchStep.ACTIVATE)}"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</layout>
|
|
@ -25,7 +25,40 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
tools:context=".ui.MedtrumActivity">
|
tools:context=".ui.MedtrumActivity">
|
||||||
|
|
||||||
<!-- TODO some stuff here that we are waiting :) -->
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_button"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_negative"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/cancel"
|
||||||
|
android:text="@string/cancel"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/btn_positive"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:onSafeClick="@{() -> viewModel.moveStep(PatchStep.CANCEL)}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_positive"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:contentDescription="@string/string_next"
|
||||||
|
android:text="@string/string_next"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/btn_negative"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:onSafeClick="@{() -> viewModel.moveStep(PatchStep.ATTACH_PATCH)}"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -16,7 +16,16 @@
|
||||||
|
|
||||||
<!-- wizard-->
|
<!-- wizard-->
|
||||||
<string name="string_change_patch">Discard/Change Patch</string> <!-- TODO check-->
|
<string name="string_change_patch">Discard/Change Patch</string> <!-- TODO check-->
|
||||||
|
<string name="string_next">Next</string>
|
||||||
<string name="string_start_prime">Start priming</string>
|
<string name="string_start_prime">Start priming</string>
|
||||||
|
<string name="string_start_activate">Start activation</string>
|
||||||
|
<string name="string_start_complete">Complete</string>
|
||||||
|
|
||||||
|
<string name ="step_prepare_patch">Prepare patch</string>
|
||||||
|
<string name ="step_prime">Priming</string>
|
||||||
|
<string name ="step_attach">Attach patch</string>
|
||||||
|
<string name ="step_activate">Activation</string>
|
||||||
|
<string name ="step_complete">Complete</string>
|
||||||
|
|
||||||
<!-- settings-->
|
<!-- settings-->
|
||||||
<string name="snInput_title">SN</string>
|
<string name="snInput_title">SN</string>
|
||||||
|
|
|
@ -70,6 +70,7 @@ class ActivatePacketTest : MedtrumTestBase() {
|
||||||
assertEquals(expectedBasalSequence, medtrumPump.lastBasalSequence)
|
assertEquals(expectedBasalSequence, medtrumPump.lastBasalSequence)
|
||||||
assertEquals(expectedBasalPatchId, medtrumPump.lastBasalPatchId)
|
assertEquals(expectedBasalPatchId, medtrumPump.lastBasalPatchId)
|
||||||
assertEquals(expectedBasalStart, medtrumPump.lastBasalStartTime)
|
assertEquals(expectedBasalStart, medtrumPump.lastBasalStartTime)
|
||||||
|
assertEquals(basalProfile, medtrumPump.actualBasalProfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
|
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
|
||||||
|
|
|
@ -32,4 +32,43 @@ class SetBasalProfilePacketTest : MedtrumTestBase() {
|
||||||
val expected = byteArrayOf(opCode.toByte()) + 1.toByte() + basalProfile
|
val expected = byteArrayOf(opCode.toByte()) + 1.toByte() + basalProfile
|
||||||
assertEquals(expected.contentToString(), result.contentToString())
|
assertEquals(expected.contentToString(), result.contentToString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
|
||||||
|
// Inputs
|
||||||
|
val repsonse = byteArrayOf(18, 21, 16, 0, 0, 0, 1, 22, 0, 3, 0, -110, 0, -32, -18, 88, 17)
|
||||||
|
val basalProfile = byteArrayOf(8, 2, 3, 4, -1, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
// Call
|
||||||
|
val packet = SetBasalProfilePacket(packetInjector, basalProfile)
|
||||||
|
val result = packet.handleResponse(repsonse)
|
||||||
|
|
||||||
|
// Expected values
|
||||||
|
val expectedBasalType = 1
|
||||||
|
val expectedBasalRate = 1.1
|
||||||
|
val expectedBasalSequence = 3
|
||||||
|
val expectedStartTime = 1679575392L
|
||||||
|
val expectedPatchId = 146
|
||||||
|
|
||||||
|
assertTrue(result)
|
||||||
|
assertEquals(expectedBasalType, medtrumPump.lastBasalType)
|
||||||
|
assertEquals(expectedBasalRate, medtrumPump.lastBasalRate, 0.01)
|
||||||
|
assertEquals(expectedBasalSequence, medtrumPump.lastBasalSequence)
|
||||||
|
assertEquals(expectedStartTime, medtrumPump.lastBasalStartTime)
|
||||||
|
assertEquals(expectedPatchId, medtrumPump.lastBasalPatchId)
|
||||||
|
assertEquals(basalProfile, medtrumPump.actualBasalProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
|
||||||
|
// Inputs
|
||||||
|
val response = byteArrayOf(18, 21, 16, 0, 0, 0, 1, 22, 0, 3, 0, -110, 0, -32, -18, 88)
|
||||||
|
val basalProfile = byteArrayOf(8, 2, 3, 4, -1, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
// Call
|
||||||
|
val packet = SetBasalProfilePacket(packetInjector, basalProfile)
|
||||||
|
val result = packet.handleResponse(response)
|
||||||
|
|
||||||
|
// Expected values
|
||||||
|
assertFalse(result)
|
||||||
|
assertTrue(packet.failed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue