Deactivation, better connection flow

This commit is contained in:
jbr7rr 2023-04-15 15:23:26 +02:00
parent fff833dae3
commit 61e873dbcc
25 changed files with 582 additions and 177 deletions

View file

@ -410,6 +410,7 @@ enum class PumpType {
baseBasalSpecialSteps = null, baseBasalSpecialSteps = null,
pumpCapability = PumpCapability.MedtrumCapabilities, pumpCapability = PumpCapability.MedtrumCapabilities,
isPatchPump = true, isPatchPump = true,
maxReservoirReading = 400,
source = Source.Medtrum source = Source.Medtrum
); );

View file

@ -52,8 +52,7 @@ import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton class MedtrumPlugin @Inject constructor(
class MedtrumPlugin @Inject constructor(
injector: HasAndroidInjector, injector: HasAndroidInjector,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
rh: ResourceHelper, rh: ResourceHelper,
@ -81,8 +80,6 @@ class MedtrumPlugin @Inject constructor(
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private var medtrumService: MedtrumService? = null private var medtrumService: MedtrumService? = null
private var mPumpType: PumpType = PumpType.MEDTRUM_NANO
private val mPumpDescription = PumpDescription(mPumpType)
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
@ -120,7 +117,7 @@ class MedtrumPlugin @Inject constructor(
} }
override fun isInitialized(): Boolean { override fun isInitialized(): Boolean {
return medtrumPump.pumpState > MedtrumPumpState.EJECTED return medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED
} }
override fun isSuspended(): Boolean { override fun isSuspended(): Boolean {
@ -132,7 +129,8 @@ class MedtrumPlugin @Inject constructor(
} }
override fun isConnected(): Boolean { override fun isConnected(): Boolean {
return if (!isInitialized()) true else medtrumService?.isConnected ?: true // This is a workaround to prevent AAPS to trigger connects when we are initializing // This is a workaround to prevent AAPS to trigger connects when we have no patch activated
return if (!medtrumPump.patchActivated) true else medtrumService?.isConnected ?: false
} }
override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false
@ -142,7 +140,7 @@ class MedtrumPlugin @Inject constructor(
} }
override fun connect(reason: String) { override fun connect(reason: String) {
if (isInitialized()) { if (medtrumPump.patchActivated) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason") aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
aapsLogger.debug(LTag.PUMP, "Medtrum connect - service::$medtrumService") aapsLogger.debug(LTag.PUMP, "Medtrum connect - service::$medtrumService")
// aapsLogger.debug(LTag.PUMP, "Medtrum connect - mDeviceSN:$mDeviceSN") // aapsLogger.debug(LTag.PUMP, "Medtrum connect - mDeviceSN:$mDeviceSN")
@ -166,6 +164,7 @@ class MedtrumPlugin @Inject constructor(
} }
override fun getPumpStatus(reason: String) { override fun getPumpStatus(reason: String) {
aapsLogger.debug(LTag.PUMP, "Medtrum getPumpStatus - reason:$reason")
if (isInitialized()) { if (isInitialized()) {
medtrumService?.readPumpStatus() medtrumService?.readPumpStatus()
} }
@ -202,14 +201,14 @@ class MedtrumPlugin @Inject constructor(
} }
override fun lastDataTime(): Long { override fun lastDataTime(): Long {
return 0 // TODO return medtrumPump.lastTimeReceivedFromPump * 1000L
} }
override val baseBasalRate: Double override val baseBasalRate: Double
get() = 0.0 // TODO get() = 0.0 // TODO
override val reservoirLevel: Double override val reservoirLevel: Double
get() = 0.0 // TODO get() = medtrumPump.reservoir
override val batteryLevel: Int override val batteryLevel: Int
get() = 0 // TODO get() = 0 // TODO
@ -228,14 +227,12 @@ 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).success(false).enacted(false) return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum driver does not support percentage temp basals")
.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).success(false).enacted(false) return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum driver does not support extended boluses")
.comment("Medtrum driver does not support extended boluses")
} }
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
@ -255,15 +252,15 @@ class MedtrumPlugin @Inject constructor(
} }
override fun model(): PumpType { override fun model(): PumpType {
return mPumpType return medtrumPump.pumpType
} }
override fun serialNumber(): String { override fun serialNumber(): String {
return "0" // TODO return medtrumPump.pumpSN.toString(radix = 16)
} }
override val pumpDescription: PumpDescription override val pumpDescription: PumpDescription
get() = mPumpDescription get() = PumpDescription(medtrumPump.pumpType)
override fun shortStatus(veryShort: Boolean): String { override fun shortStatus(veryShort: Boolean): String {
return ""// TODO return ""// TODO

View file

@ -1,13 +1,9 @@
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.profile.Instantiator import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.profile.Profile import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileStore
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.defs.PumpType import info.nightscout.interfaces.pump.defs.PumpType
import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.AlarmSetting import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray import info.nightscout.pump.medtrum.extension.toByteArray
@ -15,7 +11,6 @@ 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 info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject import javax.inject.Inject
@ -26,31 +21,44 @@ import kotlin.math.round
class MedtrumPump @Inject constructor( class MedtrumPump @Inject constructor(
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val sp: SP, private val sp: SP,
private val dateUtil: DateUtil, private val dateUtil: DateUtil
private val instantiator: Instantiator
) { ) {
// Connection state flow
private val _connectionState = MutableStateFlow(ConnectionState.DISCONNECTED)
val connectionStateFlow: StateFlow<ConnectionState> = _connectionState
var connectionState: ConnectionState
get() = _connectionState.value
set(value) {
_connectionState.value = value
}
// Pump state flow // Pump state flow
// TODO We might want to save this in SP, or at least get activated state from SP
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE) private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
val pumpStateFlow: StateFlow<MedtrumPumpState> = _pumpState val pumpStateFlow: StateFlow<MedtrumPumpState> = _pumpState
var pumpState: MedtrumPumpState var pumpState: MedtrumPumpState
get() = _pumpState.value get() = _pumpState.value
set(value) { set(value) {
_pumpState.value = value _pumpState.value = value
} }
var _patchActivated = false
val patchActivated: Boolean
get() = _patchActivated
// Prime progress as state flow // Prime progress as state flow
private val _primeProgress = MutableStateFlow(0) private val _primeProgress = MutableStateFlow(0)
val primeProgressFlow: StateFlow<Int> = _primeProgress val primeProgressFlow: StateFlow<Int> = _primeProgress
var primeProgress: Int var primeProgress: Int
get() = _primeProgress.value get() = _primeProgress.value
set(value) { set(value) {
_primeProgress.value = value _primeProgress.value = value
} }
var pumpSN = 0L
val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection
var patchSessionToken = 0L
// 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 // 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 actualBasalProfile = byteArrayOf(0)
var patchId = 0L var patchId = 0L
@ -86,6 +94,19 @@ class MedtrumPump @Inject constructor(
var desiredHourlyMaxInsulin: Int = 40 var desiredHourlyMaxInsulin: Int = 40
var desiredDailyMaxInsulin: Int = 180 var desiredDailyMaxInsulin: Int = 180
fun setPatchActivatedState(activated: Boolean) {
aapsLogger.debug(LTag.PUMP, "setPatchActivatedState: $activated")
_patchActivated = activated
sp.putBoolean(R.string.key_patch_activated, activated)
}
/** When the activation/deactivation screen, and the connection flow needs to be controlled,
* this can be used to set the ActivatedState without saving to SP, So when app is force closed the state is still maintained */
fun setPatchActivatedStateTemp(activated: Boolean) {
aapsLogger.debug(LTag.PUMP, "setPatchActivatedStateTemp: $activated")
_patchActivated = activated
}
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? { fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
val list = nsProfile.getBasalValues() val list = nsProfile.getBasalValues()
var basals = byteArrayOf() var basals = byteArrayOf()

View file

@ -0,0 +1,7 @@
package info.nightscout.pump.medtrum.code
enum class ConnectionState {
CONNECTED,
DISCONNECTED,
CONNECTING;
}

View file

@ -1,11 +1,9 @@
package info.nightscout.pump.medtrum.code package info.nightscout.pump.medtrum.code
enum class PatchStep { enum class PatchStep {
SAFE_DEACTIVATION, START_DEACTIVATION,
MANUALLY_TURNING_OFF_ALARM, DEACTIVATE,
DISCARDED, DEACTIVATION_COMPLETE,
DISCARDED_FOR_CHANGE,
DISCARDED_FROM_ALARM,
PREPARE_PATCH, PREPARE_PATCH,
PRIME, PRIME,
ATTACH_PATCH, ATTACH_PATCH,

View file

@ -1,6 +1,8 @@
package info.nightscout.pump.medtrum.comm.packets package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.pump.DetailedBolusInfo
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.pump.medtrum.MedtrumPump import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.ACTIVATE import info.nightscout.pump.medtrum.comm.enums.CommandType.ACTIVATE
import info.nightscout.pump.medtrum.extension.toByteArray import info.nightscout.pump.medtrum.extension.toByteArray
@ -16,6 +18,7 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
@Inject lateinit var medtrumPump: MedtrumPump @Inject lateinit var medtrumPump: MedtrumPump
@Inject lateinit var tddCalculator: TddCalculator @Inject lateinit var tddCalculator: TddCalculator
@Inject lateinit var pumpSync: PumpSync
companion object { companion object {
@ -95,6 +98,22 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
medtrumPump.actualBasalProfile = basalProfile medtrumPump.actualBasalProfile = basalProfile
// TODO: Handle history entry // TODO: Handle history entry
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time) medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
// Update the pump in the database, technically this is not a new pump only new patch, but still TBR's etc need to be cannceled
pumpSync.connectNewPump()
// Sync canula change
pumpSync.insertTherapyEventIfNewWithTimestamp(
timestamp = System.currentTimeMillis(),
type = DetailedBolusInfo.EventType.CANNULA_CHANGE,
pumpType = medtrumPump.pumpType,
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
pumpSync.insertTherapyEventIfNewWithTimestamp(
timestamp = System.currentTimeMillis(),
type = DetailedBolusInfo.EventType.INSULIN_CHANGE,
pumpType = medtrumPump.pumpType,
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
} }
return success return success

View file

@ -1,12 +1,16 @@
package info.nightscout.pump.medtrum.comm.packets 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.comm.enums.CommandType.AUTH_REQ import info.nightscout.pump.medtrum.comm.enums.CommandType.AUTH_REQ
import info.nightscout.pump.medtrum.encryption.Crypt import info.nightscout.pump.medtrum.encryption.Crypt
import info.nightscout.pump.medtrum.extension.toByteArray import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt import info.nightscout.pump.medtrum.extension.toInt
import javax.inject.Inject
class AuthorizePacket(injector: HasAndroidInjector, private val deviceSerial: Long) : MedtrumPacket(injector) { class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@Inject lateinit var medtrumPump: MedtrumPump
var deviceType: Int = 0 var deviceType: Int = 0
var swVersion: String = "" var swVersion: String = ""
@ -30,8 +34,8 @@ class AuthorizePacket(injector: HasAndroidInjector, private val deviceSerial: Lo
override fun getRequest(): ByteArray { override fun getRequest(): ByteArray {
val role = 2 // Fixed to 2 for pump val role = 2 // Fixed to 2 for pump
val key = Crypt().keyGen(deviceSerial) val key = Crypt().keyGen(medtrumPump.pumpSN)
return byteArrayOf(opCode) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4) return byteArrayOf(opCode) + byteArrayOf(role.toByte()) + medtrumPump.patchSessionToken.toByteArray(4) + key.toByteArray(4)
} }
override fun handleResponse(data: ByteArray): Boolean { override fun handleResponse(data: ByteArray): Boolean {

View file

@ -115,15 +115,19 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_BASAL != 0) { if (fieldMask and MASK_BASAL != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Basal notification received") aapsLogger.debug(LTag.PUMPCOMM, "Basal notification received")
var basalType = data.copyOfRange(offset, offset + 1) var basalType = data.copyOfRange(offset, offset + 1).toInt()
var basalSequence = data.copyOfRange(offset + 1, offset + 3) var basalSequence = data.copyOfRange(offset + 1, offset + 3).toInt()
var basalInterval = data.copyOfRange(offset + 3, offset + 7) var basalPatchId = data.copyOfRange(offset + 3, offset + 5).toInt()
var basalRateAndDelivery = data.copyOfRange(offset + 7, offset + 10).toInt() var basalInterval = data.copyOfRange(offset + 5, offset + 9).toInt()
var basalRate = basalRateAndDelivery and 0xFFF var basalRateAndDelivery = data.copyOfRange(offset + 9, offset + 12).toInt()
var basalDelivery = (basalRateAndDelivery shr 12) var basalRate = (basalRateAndDelivery and 0xFFF) * 0.05
aapsLogger.debug(LTag.PUMPCOMM, "Basal type: $basalType, basal sequence: $basalSequence, basal interval: $basalInterval, basal rate: $basalRate, basal delivery: $basalDelivery") var basalDelivery = (basalRateAndDelivery shr 12) * 0.05
aapsLogger.debug(
LTag.PUMPCOMM,
"Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal interval: $basalInterval, basal rate: $basalRate, basal delivery: $basalDelivery"
)
// TODO Sync basal flow // TODO Sync basal flow
offset += 10 offset += 12
} }
if (fieldMask and MASK_SETUP != 0) { if (fieldMask and MASK_SETUP != 0) {

View file

@ -10,6 +10,7 @@ class SetBolusMotorPacket(injector: HasAndroidInjector) : MedtrumPacket(injector
} }
override fun getRequest(): ByteArray { override fun getRequest(): ByteArray {
// TODO CHECK! Seems to be a feature? to set the bolus to vibrate? TEST!
return byteArrayOf(opCode) + 0.toByte() return byteArrayOf(opCode) + 0.toByte()
} }
} }

View file

@ -6,6 +6,7 @@ import info.nightscout.pump.medtrum.comm.enums.CommandType.SYNCHRONIZE
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import javax.inject.Inject import javax.inject.Inject
@ -37,6 +38,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
aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: state: $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)

View file

@ -9,8 +9,10 @@ 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.MedtrumActivateFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumDeactivatePatchFragment
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.androidaps.plugins.pump.eopatch.ui.MedtrumStartDeactivationFragment
import info.nightscout.pump.medtrum.services.MedtrumService import info.nightscout.pump.medtrum.services.MedtrumService
import info.nightscout.pump.medtrum.ui.MedtrumActivity import info.nightscout.pump.medtrum.ui.MedtrumActivity
import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
@ -50,6 +52,14 @@ abstract class MedtrumModule {
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun contributesMedtrumOverviewFragment(): MedtrumOverviewFragment abstract fun contributesMedtrumOverviewFragment(): MedtrumOverviewFragment
@FragmentScope
@ContributesAndroidInjector
internal abstract fun contributesStartDeactivationFragment(): MedtrumStartDeactivationFragment
@FragmentScope
@ContributesAndroidInjector
internal abstract fun contributesDeactivatePatchFragment(): MedtrumDeactivatePatchFragment
@FragmentScope @FragmentScope
@ContributesAndroidInjector @ContributesAndroidInjector
internal abstract fun contributesPreparePatchFragment(): MedtrumPreparePatchFragment internal abstract fun contributesPreparePatchFragment(): MedtrumPreparePatchFragment

View file

@ -4,6 +4,7 @@ import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toLong import info.nightscout.pump.medtrum.extension.toLong
class Crypt { class Crypt {
private val RIJNDEAL_S_BOX: IntArray = intArrayOf(99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22) private val RIJNDEAL_S_BOX: IntArray = intArrayOf(99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22)
private val RIJNDEAL_INVERSE_S_BOX: IntArray = intArrayOf(82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125) private val RIJNDEAL_INVERSE_S_BOX: IntArray = intArrayOf(82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125)
@ -14,16 +15,11 @@ class Crypt {
return simpleCrypt(key) return simpleCrypt(key)
} }
fun randomGen(input: Long): Long { fun generateRandomToken(): Long {
val A = 16807 val randomBytes = ByteArray(4)
val Q = 127773 val random = java.security.SecureRandom()
val R = 2836 random.nextBytes(randomBytes)
val tmp1 = input / Q return randomBytes.toLong()
var ret = (input - (tmp1 * Q)) * A - (tmp1 * R)
if (ret < 0) {
ret += 2147483647L
}
return ret
} }
private fun simpleCrypt(inputData: Long): Long { private fun simpleCrypt(inputData: Long): Long {
@ -42,6 +38,18 @@ class Crypt {
return temp xor MED_CIPHER return temp xor MED_CIPHER
} }
private fun randomGen(input: Long): Long {
val A = 16807
val Q = 127773
val R = 2836
val tmp1 = input / Q
var ret = (input - (tmp1 * Q)) * A - (tmp1 * R)
if (ret < 0) {
ret += 2147483647L
}
return ret
}
private fun changeByTable(inputData: Long, tableData: IntArray): Long { private fun changeByTable(inputData: Long, tableData: IntArray): Long {
val value = inputData.toByteArray(4) val value = inputData.toByteArray(4)
val results = ByteArray(4) val results = ByteArray(4)

View file

@ -18,6 +18,8 @@ import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.medtrum.MedtrumPlugin import info.nightscout.pump.medtrum.MedtrumPlugin
import info.nightscout.pump.medtrum.MedtrumPump import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.comm.packets.* import info.nightscout.pump.medtrum.comm.packets.*
import info.nightscout.pump.medtrum.extension.toInt import info.nightscout.pump.medtrum.extension.toInt
@ -67,14 +69,13 @@ class MedtrumService : DaggerService(), BLECommCallback {
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private val mBinder: IBinder = LocalBinder() private val mBinder: IBinder = LocalBinder()
private var mDeviceSN: Long = 0
private var currentState: State = IdleState() private var currentState: State = IdleState()
private var mPacket: MedtrumPacket? = null private var mPacket: MedtrumPacket? = null
var isConnected = false
var isConnecting = false
// TODO: Stuff like this in a settings class? val isConnected: Boolean
private var mLastDeviceTime: Long = 0 get() = medtrumPump.connectionState == ConnectionState.CONNECTED
val isConnecting: Boolean
get() = medtrumPump.connectionState == ConnectionState.CONNECTING
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -88,11 +89,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> .subscribe({ event ->
if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput))) { if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput))) {
pumpSync.connectNewPump()
changePump() changePump()
} }
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
changePump() changePump()
// TODO: We should probably listen to the pump state as well and handle some state changes? Or do we handle that in the packets or medtrumPump?
} }
override fun onDestroy() { override fun onDestroy() {
@ -101,12 +102,13 @@ class MedtrumService : DaggerService(), BLECommCallback {
} }
fun connect(from: String): Boolean { fun connect(from: String): Boolean {
aapsLogger.debug(LTag.PUMP, "connect: called!") aapsLogger.debug(LTag.PUMP, "connect: called from: $from")
if (currentState is IdleState) { if (currentState is IdleState) {
isConnecting = true medtrumPump.connectionState = ConnectionState.CONNECTING
isConnected = false if (medtrumPump.patchActivated) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING)) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING))
return bleComm.connect(from, mDeviceSN) }
return bleComm.connect(from, medtrumPump.pumpSN)
} else { } else {
aapsLogger.error(LTag.PUMPCOMM, "Connect attempt when in non Idle state from: $from") aapsLogger.error(LTag.PUMPCOMM, "Connect attempt when in non Idle state from: $from")
return false return false
@ -119,12 +121,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
} }
fun startActivate(): Boolean { 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 profile = profileFunction.getProfile()?.let { medtrumPump.buildMedtrumProfileArray(it) }
val packet = profile?.let { ActivatePacket(injector, it) } val packet = profile?.let { ActivatePacket(injector, it) }
return packet?.let { sendPacketAndGetResponse(it) } == true return packet?.let { sendPacketAndGetResponse(it) } == true
} }
fun deactivatePatch(): Boolean {
return sendPacketAndGetResponse(StopPatchPacket(injector))
}
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()
@ -136,7 +141,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
} }
fun readPumpStatus() { fun readPumpStatus() {
// TODO // TODO read pump history
} }
fun loadEvents(): PumpEnactResult { fun loadEvents(): PumpEnactResult {
@ -150,12 +155,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
return result return result
} }
fun setUserSettings(): PumpEnactResult {
// TODO need this? Check
val result = PumpEnactResult(injector)
return result
}
fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean { fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean {
if (!isConnected) return false if (!isConnected) return false
// TODO // TODO
@ -174,15 +173,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun changePump() { fun changePump() {
aapsLogger.debug(LTag.PUMP, "changePump: called!") aapsLogger.debug(LTag.PUMP, "changePump: called!")
try { try {
mDeviceSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16) medtrumPump.pumpSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
} 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? Getting status should be enough? medtrumPump.setPatchActivatedState(sp.getBoolean(R.string.key_patch_activated, false))
when (currentState) { medtrumPump.patchSessionToken = sp.getLong(R.string.key_session_token, 0)
is IdleState -> connect("changePump") if (medtrumPump.patchActivated) {
// is ReadyState -> disconnect("changePump") aapsLogger.debug(LTag.PUMP, "changePump: Patch is already activated, setting as ACTIVE")
else -> null // TODO: What to do here? Abort stuff? medtrumPump.pumpState = MedtrumPumpState.ACTIVE // Set inital status as active will be updated on first connection
} }
} }
@ -260,10 +259,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
open fun onDisconnected() { open fun onDisconnected() {
aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected") aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected")
isConnecting = false medtrumPump.connectionState = ConnectionState.DISCONNECTED
isConnected = false if (medtrumPump.patchActivated) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED)) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
}
// TODO: Check flow for this // TODO: Check flow for this
toState(IdleState()) toState(IdleState())
} }
@ -277,7 +276,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() { override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached IdleState") aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached IdleState")
connect("IdleState onEnter")
} }
override fun onConnected() { override fun onConnected() {
@ -287,7 +285,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onDisconnected() { override fun onDisconnected() {
super.onDisconnected() super.onDisconnected()
connect("IdleState onDisconnected")
} }
} }
@ -296,7 +293,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() { override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached AuthState") aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached AuthState")
mPacket = AuthorizePacket(injector, mDeviceSN) mPacket = AuthorizePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) } mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
} }
@ -427,7 +424,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onIndication(data: ByteArray) { override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) { if (mPacket?.handleResponse(data) == true) {
// Succes! // Succes!
// TODO: Handle pump state parameters
toState(SubscribeState()) toState(SubscribeState())
} else if (mPacket?.failed == true) { } else if (mPacket?.failed == true) {
// Failure // Failure
@ -464,9 +460,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() { override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!") aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!")
// Now we are fully connected and authenticated and we can start sending commands. Let AAPS know // Now we are fully connected and authenticated and we can start sending commands. Let AAPS know
isConnecting = false medtrumPump.connectionState = ConnectionState.CONNECTED
isConnected = true if (medtrumPump.patchActivated) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED)) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
}
} }
} }

View file

@ -11,8 +11,10 @@ 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.MedtrumActivateFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumDeactivatePatchFragment
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.androidaps.plugins.pump.eopatch.ui.MedtrumStartDeactivationFragment
import info.nightscout.core.utils.extensions.safeGetSerializableExtra import info.nightscout.core.utils.extensions.safeGetSerializableExtra
import info.nightscout.pump.medtrum.R import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.PatchStep import info.nightscout.pump.medtrum.code.PatchStep
@ -42,13 +44,16 @@ class MedtrumActivity : MedtrumBaseActivity<ActivityMedtrumBinding>() {
patchStep.observe(this@MedtrumActivity) { patchStep.observe(this@MedtrumActivity) {
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.ATTACH_PATCH -> setupViewFragment(MedtrumAttachPatchFragment.newInstance())
PatchStep.ACTIVATE -> setupViewFragment(MedtrumActivateFragment.newInstance()) PatchStep.ACTIVATE -> setupViewFragment(MedtrumActivateFragment.newInstance())
PatchStep.COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish PatchStep.COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
PatchStep.CANCEL -> this@MedtrumActivity.finish() PatchStep.CANCEL -> this@MedtrumActivity.finish()
else -> Unit PatchStep.START_DEACTIVATION -> setupViewFragment(MedtrumStartDeactivationFragment.newInstance())
PatchStep.DEACTIVATE -> setupViewFragment(MedtrumDeactivatePatchFragment.newInstance())
PatchStep.DEACTIVATION_COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
else -> Unit
} }
} }
} }
@ -85,8 +90,7 @@ class MedtrumActivity : MedtrumBaseActivity<ActivityMedtrumBinding>() {
const val EXTRA_START_PATCH_STEP = "EXTRA_START_PATCH_FRAGMENT_UI" const val EXTRA_START_PATCH_STEP = "EXTRA_START_PATCH_FRAGMENT_UI"
const val EXTRA_START_FROM_MENU = "EXTRA_START_FROM_MENU" const val EXTRA_START_FROM_MENU = "EXTRA_START_FROM_MENU"
@JvmStatic @JvmStatic fun createIntentFromMenu(context: Context, patchStep: PatchStep): Intent {
fun createIntentFromMenu(context: Context, patchStep: PatchStep): Intent {
return Intent(context, MedtrumActivity::class.java).apply { return Intent(context, MedtrumActivity::class.java).apply {
putExtra(EXTRA_START_PATCH_STEP, patchStep) putExtra(EXTRA_START_PATCH_STEP, patchStep)
putExtra(EXTRA_START_FROM_MENU, true) putExtra(EXTRA_START_FROM_MENU, true)

View file

@ -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.FragmentMedtrumDeactivatePatchBinding
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 MedtrumDeactivatePatchFragment : MedtrumBaseFragment<FragmentMedtrumDeactivatePatchBinding>() {
@Inject lateinit var aapsLogger: AAPSLogger
companion object {
fun newInstance(): MedtrumDeactivatePatchFragment = MedtrumDeactivatePatchFragment()
}
override fun getLayoutId(): Int = R.layout.fragment_medtrum_deactivate_patch
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
aapsLogger.debug(LTag.PUMP, "MedtrumDeactivatePatchFragment onViewCreated")
binding.apply {
viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
viewModel?.apply {
setupStep.observe(viewLifecycleOwner) {
when (it) {
MedtrumViewModel.SetupStep.STOPPED -> btnPositive.visibility = View.VISIBLE
MedtrumViewModel.SetupStep.ERROR -> {
ToastUtils.errorToast(requireContext(), "Error deactivate") // TODO: String resource and show error message
moveStep(PatchStep.CANCEL)
}
else -> Unit // Nothing to do here
}
}
deactivatePatch()
}
}
}
}

View file

@ -43,13 +43,19 @@ 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 { EventType.ACTIVATION_CLICKED -> requireContext().apply {
val step = convertToPatchStep(medtrumPump.pumpState) val step = convertToPatchStep(medtrumPump.pumpState)
// TODO is stil needed?
if (step != PatchStep.PREPARE_PATCH) { if (step != PatchStep.PREPARE_PATCH) {
aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step") aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step")
} }
startActivity(MedtrumActivity.createIntentFromMenu(this, step)) } startActivity(MedtrumActivity.createIntentFromMenu(this, step))
else -> Unit }
EventType.DEACTIVATION_CLICKED -> requireContext().apply {
startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.START_DEACTIVATION))
}
else -> Unit
} }
} }

View file

@ -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.FragmentMedtrumStartDeactivationBinding
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 MedtrumStartDeactivationFragment : MedtrumBaseFragment<FragmentMedtrumStartDeactivationBinding>() {
@Inject lateinit var aapsLogger: AAPSLogger
companion object {
fun newInstance(): MedtrumStartDeactivationFragment = MedtrumStartDeactivationFragment()
}
override fun getLayoutId(): Int = R.layout.fragment_medtrum_start_deactivation
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
aapsLogger.debug(LTag.PUMP, "MedtrumStartDeactivationFragment onViewCreated")
binding.apply {
viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
viewModel?.apply {
setupStep.observe(viewLifecycleOwner) {
when (it) {
MedtrumViewModel.SetupStep.READY_DEACTIVATE -> btnPositive.visibility = View.VISIBLE
MedtrumViewModel.SetupStep.ERROR -> {
ToastUtils.errorToast(requireContext(), "Error deactivate") // TODO: String resource and show error message
moveStep(PatchStep.CANCEL)
}
else -> Unit // Nothing to do here
}
}
startDeactivation()
}
}
}
}

View file

@ -10,6 +10,7 @@ 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.MedtrumPump
import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState 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
@ -20,6 +21,7 @@ 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.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@ -32,7 +34,6 @@ class MedtrumOverviewViewModel @Inject constructor(
private val medtrumPump: MedtrumPump private val medtrumPump: MedtrumPump
) : BaseViewModel<MedtrumBaseNavigator>() { ) : BaseViewModel<MedtrumBaseNavigator>() {
private var disposable: CompositeDisposable = CompositeDisposable()
private val scope = CoroutineScope(Dispatchers.Default) private val scope = CoroutineScope(Dispatchers.Default)
private val _eventHandler = SingleLiveEvent<UIEvent<EventType>>() private val _eventHandler = SingleLiveEvent<UIEvent<EventType>>()
@ -48,29 +49,28 @@ class MedtrumOverviewViewModel @Inject constructor(
get() = _isPatchActivated get() = _isPatchActivated
init { init {
// TODO proper connection state from medtrumPump scope.launch {
disposable += rxBus medtrumPump.connectionStateFlow.collect { state ->
.toObservable(EventPumpStatusChanged::class.java) aapsLogger.debug(LTag.PUMP, "MedtrumViewModel connectionStateFlow: $state")
.observeOn(aapsSchedulers.main) when (state) {
.subscribe({ ConnectionState.CONNECTING -> {
_bleStatus.value = when (it.status) { _bleStatus.postValue("{fa-bluetooth-b spin}")
EventPumpStatusChanged.Status.CONNECTING -> }
"{fa-bluetooth-b spin} ${it.secondsElapsed}s"
EventPumpStatusChanged.Status.CONNECTED -> ConnectionState.CONNECTED -> {
"{fa-bluetooth}" _bleStatus.postValue("{fa-bluetooth}")
}
EventPumpStatusChanged.Status.DISCONNECTED -> ConnectionState.DISCONNECTED -> {
"{fa-bluetooth-b}" _bleStatus.postValue("{fa-bluetooth-b}")
}
else -> }
"" }
} }
}, fabricPrivacy::logException)
scope.launch { scope.launch {
medtrumPump.pumpStateFlow.collect { state -> medtrumPump.pumpStateFlow.collect { state ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state") aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
if (state > MedtrumPumpState.EJECTED) { if (state > MedtrumPumpState.EJECTED && state < MedtrumPumpState.STOPPED) {
_isPatchActivated.postValue(true) _isPatchActivated.postValue(true)
} else { } else {
_isPatchActivated.postValue(false) _isPatchActivated.postValue(false)
@ -79,6 +79,11 @@ class MedtrumOverviewViewModel @Inject constructor(
} }
} }
override fun onCleared() {
super.onCleared()
scope.cancel()
}
fun onClickActivation() { fun onClickActivation() {
aapsLogger.debug(LTag.PUMP, "Start Patch clicked!") aapsLogger.debug(LTag.PUMP, "Start Patch clicked!")
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
@ -91,6 +96,6 @@ class MedtrumOverviewViewModel @Inject constructor(
fun onClickDeactivation() { fun onClickDeactivation() {
aapsLogger.debug(LTag.PUMP, "Stop Patch clicked!") aapsLogger.debug(LTag.PUMP, "Stop Patch clicked!")
// TODO _eventHandler.postValue(UIEvent(EventType.DEACTIVATION_CLICKED))
} }
} }

View file

@ -6,10 +6,12 @@ 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.MedtrumPump
import info.nightscout.pump.medtrum.R import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
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.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.encryption.Crypt
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
@ -22,6 +24,7 @@ import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@ -54,37 +57,74 @@ class MedtrumViewModel @Inject constructor(
private var mInitPatchStep: PatchStep? = null private var mInitPatchStep: PatchStep? = null
init { init {
// TODO destroy scope
scope.launch { scope.launch {
medtrumPump.pumpStateFlow.collect { state -> medtrumPump.connectionStateFlow.collect { state ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state") aapsLogger.debug(LTag.PUMP, "MedtrumViewModel connectionStateFlow: $state")
when (state) { if (patchStep.value != null) {
MedtrumPumpState.NONE, MedtrumPumpState.IDLE -> { when (state) {
setupStep.postValue(SetupStep.INITIAL) ConnectionState.CONNECTED -> {
} if (patchStep.value == PatchStep.START_DEACTIVATION) {
updateSetupStep(SetupStep.READY_DEACTIVATE)
}
}
MedtrumPumpState.FILLED -> { ConnectionState.DISCONNECTED -> {
setupStep.postValue(SetupStep.FILLED) if (patchStep.value != PatchStep.DEACTIVATION_COMPLETE && patchStep.value != PatchStep.COMPLETE && patchStep.value != PatchStep.CANCEL) {
} medtrumService?.connect("Try reconnect from viewModel")
}
}
MedtrumPumpState.PRIMING -> { ConnectionState.CONNECTING -> {
// setupStep.postValue(SetupStep.PRIMING) }
// TODO: What to do here? start prime counter?
}
MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> {
setupStep.postValue(SetupStep.PRIMED)
}
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
setupStep.postValue(SetupStep.ACTIVATED)
}
else -> {
setupStep.postValue(SetupStep.ERROR)
} }
} }
} }
} }
scope.launch {
medtrumPump.pumpStateFlow.collect { state ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
if (patchStep.value != null) {
when (state) {
MedtrumPumpState.NONE, MedtrumPumpState.IDLE -> {
updateSetupStep(SetupStep.INITIAL)
}
MedtrumPumpState.FILLED -> {
updateSetupStep(SetupStep.FILLED)
}
MedtrumPumpState.PRIMING -> {
// updateSetupStep(SetupStep.PRIMING)
// TODO: What to do here? start prime counter?
}
MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> {
updateSetupStep(SetupStep.PRIMED)
}
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
medtrumPump.setPatchActivatedState(true)
updateSetupStep(SetupStep.ACTIVATED)
}
MedtrumPumpState.STOPPED -> {
medtrumPump.setPatchActivatedState(false)
updateSetupStep(SetupStep.STOPPED)
}
else -> {
updateSetupStep(SetupStep.ERROR)
}
}
}
}
}
}
override fun onCleared() {
super.onCleared()
scope.cancel()
} }
fun moveStep(newPatchStep: PatchStep) { fun moveStep(newPatchStep: PatchStep) {
@ -92,14 +132,27 @@ 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 {
// } }
// TODO: For DEACTIVATE STATE we might want to move to force cancel screen
if (oldPatchStep == PatchStep.START_DEACTIVATION || oldPatchStep == PatchStep.DEACTIVATE) {
// Deactivation was canceled
medtrumPump.setPatchActivatedStateTemp(true)
}
} }
else -> null PatchStep.COMPLETE -> {
}?.let { if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Complete") else {
// TODO Update lifecycle }
}
PatchStep.DEACTIVATION_COMPLETE -> {
if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("DeactivationComplete") else {
}
}
else -> {}
} }
} }
@ -113,12 +166,20 @@ class MedtrumViewModel @Inject constructor(
} }
fun preparePatch() { fun preparePatch() {
// TODO When we dont need to connect what needs to be done here? if (medtrumPump.patchActivated == true) {
aapsLogger.warn(LTag.PUMP, "preparePatch: already activated! conflicting state?")
// In this case user could have removed the patch without deactivating it?
medtrumPump.setPatchActivatedState(false)
}
// New session, generate new session token
aapsLogger.info(LTag.PUMP, "preparePatch: new session")
medtrumPump.patchSessionToken = Crypt().generateRandomToken()
sp.putLong(R.string.key_session_token, medtrumPump.patchSessionToken)
// Connect to pump
medtrumService?.connect("PreparePatch") medtrumService?.connect("PreparePatch")
} }
fun startPrime() { fun startPrime() {
// TODO: Get result from service
if (medtrumPump.pumpState == MedtrumPumpState.PRIMING) { if (medtrumPump.pumpState == MedtrumPumpState.PRIMING) {
aapsLogger.info(LTag.PUMP, "startPrime: already priming!") aapsLogger.info(LTag.PUMP, "startPrime: already priming!")
} else { } else {
@ -126,7 +187,7 @@ class MedtrumViewModel @Inject constructor(
aapsLogger.info(LTag.PUMP, "startPrime: success!") aapsLogger.info(LTag.PUMP, "startPrime: success!")
} else { } else {
aapsLogger.info(LTag.PUMP, "startPrime: failure!") aapsLogger.info(LTag.PUMP, "startPrime: failure!")
setupStep.postValue(SetupStep.ERROR) updateSetupStep(SetupStep.ERROR)
} }
} }
} }
@ -136,20 +197,46 @@ class MedtrumViewModel @Inject constructor(
aapsLogger.info(LTag.PUMP, "startActivate: success!") aapsLogger.info(LTag.PUMP, "startActivate: success!")
} else { } else {
aapsLogger.info(LTag.PUMP, "startActivate: failure!") aapsLogger.info(LTag.PUMP, "startActivate: failure!")
setupStep.postValue(SetupStep.ERROR) updateSetupStep(SetupStep.ERROR)
}
}
fun startDeactivation() {
// Set active already to false, so UI can control the pump connection instead of AAPS pumpqueue
medtrumPump.setPatchActivatedStateTemp(false)
// Start connecting if needed
if (medtrumService?.isConnected == true) {
updateSetupStep(SetupStep.READY_DEACTIVATE)
} else if (medtrumService?.isConnecting != true) {
medtrumService?.connect("StartDeactivation")
}
// TODO: Also start timer to check if connection is made, if timed out show force forget patch
}
fun deactivatePatch() {
if (medtrumService?.deactivatePatch() == true) {
aapsLogger.info(LTag.PUMP, "deactivatePatch: success!")
} else {
aapsLogger.info(LTag.PUMP, "deactivatePatch: failure!")
// Check if this is needed, for now even when it failed, we assume the user will remove the patch and pumpbase
medtrumPump.setPatchActivatedStateTemp(true) // failed to activate, set activate state to true
// TODO: State to force forget the patch or try again
updateSetupStep(SetupStep.ERROR)
} }
} }
private fun prepareStep(step: PatchStep?): PatchStep { private fun prepareStep(step: PatchStep?): PatchStep {
// TODO Title per screen :) And proper sync with patchstate
(step ?: convertToPatchStep(medtrumPump.pumpState)).let { newStep -> (step ?: convertToPatchStep(medtrumPump.pumpState)).let { newStep ->
when (newStep) { when (newStep) {
PatchStep.PREPARE_PATCH -> R.string.step_prepare_patch PatchStep.PREPARE_PATCH -> R.string.step_prepare_patch
PatchStep.PRIME -> R.string.step_prime PatchStep.PRIME -> R.string.step_prime
PatchStep.ATTACH_PATCH -> R.string.step_attach PatchStep.ATTACH_PATCH -> R.string.step_attach
PatchStep.ACTIVATE -> R.string.step_activate PatchStep.ACTIVATE -> R.string.step_activate
PatchStep.COMPLETE -> R.string.step_complete PatchStep.COMPLETE -> R.string.step_complete
else -> _title.value PatchStep.START_DEACTIVATION, PatchStep.DEACTIVATE -> R.string.step_deactivate
PatchStep.DEACTIVATION_COMPLETE -> R.string.step_complete
else -> _title.value
}.let { }.let {
aapsLogger.info(LTag.PUMP, "prepareStep: title before cond: $it") aapsLogger.info(LTag.PUMP, "prepareStep: title before cond: $it")
if (_title.value != it) { if (_title.value != it) {
@ -164,12 +251,7 @@ class MedtrumViewModel @Inject constructor(
} }
} }
enum class SetupStep { enum class SetupStep { INITIAL, FILLED, PRIMED, ACTIVATED, ERROR, START_DEACTIVATION, STOPPED, READY_DEACTIVATE
INITIAL,
FILLED,
PRIMED,
ACTIVATED,
ERROR
} }
val setupStep = MutableLiveData<SetupStep>() val setupStep = MutableLiveData<SetupStep>()

View file

@ -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.DEACTIVATION_COMPLETE)}"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>

View file

@ -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_deactivate"
android:text="@string/string_start_deactivate"
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.DEACTIVATE)}"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>

View file

@ -3,6 +3,8 @@
<!-- MedtrumPump --> <!-- MedtrumPump -->
<string name="key_snInput" translatable="false">snInput</string> <string name="key_snInput" translatable="false">snInput</string>
<string name="key_medtrumpump_settings" translatable="false">medtrumpump_settings</string> <string name="key_medtrumpump_settings" translatable="false">medtrumpump_settings</string>
<string name="key_patch_activated" translatable="false">medtrum_patch_activated</string>
<string name="key_session_token" translatable="false">medtrum_session_token</string>
<string name="medtrum">Medtrum</string> <string name="medtrum">Medtrum</string>
<string name="medtrum_pump_shortname">MEDTRUM</string> <string name="medtrum_pump_shortname">MEDTRUM</string>
@ -20,12 +22,14 @@
<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_activate">Start activation</string>
<string name="string_start_complete">Complete</string> <string name="string_start_complete">Complete</string>
<string name="string_start_deactivate">Deactivate patch</string>
<string name ="step_prepare_patch">Prepare patch</string> <string name ="step_prepare_patch">Prepare patch</string>
<string name ="step_prime">Priming</string> <string name ="step_prime">Priming</string>
<string name ="step_attach">Attach patch</string> <string name ="step_attach">Attach patch</string>
<string name ="step_activate">Activation</string> <string name ="step_activate">Activation</string>
<string name ="step_complete">Complete</string> <string name ="step_complete">Complete</string>
<string name ="step_deactivate">Deactivation</string>
<!-- settings--> <!-- settings-->
<string name="snInput_title">SN</string> <string name="snInput_title">SN</string>

View file

@ -3,6 +3,7 @@ package info.nightscout.pump.medtrum
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.interfaces.profile.Instantiator import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.stats.TddCalculator import info.nightscout.interfaces.stats.TddCalculator
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.mockito.Mock import org.mockito.Mock
@ -12,11 +13,12 @@ open class MedtrumTestBase: TestBaseWithProfile() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var instantiator: Instantiator @Mock lateinit var instantiator: Instantiator
@Mock lateinit var tddCalculator: TddCalculator @Mock lateinit var tddCalculator: TddCalculator
@Mock lateinit var pumpSync: PumpSync
lateinit var medtrumPump: MedtrumPump lateinit var medtrumPump: MedtrumPump
@BeforeEach @BeforeEach
fun setup() { fun setup() {
medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil, instantiator) medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil)
} }
} }

View file

@ -17,6 +17,7 @@ class ActivatePacketTest : MedtrumTestBase() {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.medtrumPump = medtrumPump it.medtrumPump = medtrumPump
it.tddCalculator = tddCalculator it.tddCalculator = tddCalculator
it.pumpSync = pumpSync
} }
} }
} }
@ -35,7 +36,7 @@ class ActivatePacketTest : MedtrumTestBase() {
val result = packet.getRequest() val result = packet.getRequest()
// Expected values // Expected values
val expectedByteArray = byteArrayOf(18, 0, 0, 1, 6, 0, 0, 0, 32, 3, 16, 14, 0, 0, 1, 3, 16, 14, 0, 0, 1, 2, 12, 12, 12) val expectedByteArray = byteArrayOf(18, 0, 12, 1, 6, 0, 0, 30, 32, 3, 16, 14, 0, 0, 1, 3, 16, 14, 0, 0, 1, 2, 12, 12, 12)
assertEquals(expectedByteArray.contentToString(), result.contentToString()) assertEquals(expectedByteArray.contentToString(), result.contentToString())
} }

View file

@ -13,8 +13,9 @@ class AuthorizePacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector { private val packetInjector = HasAndroidInjector {
AndroidInjector { AndroidInjector {
if (it is MedtrumPacket) { if (it is AuthorizePacket) {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.medtrumPump = medtrumPump
} }
} }
} }
@ -22,16 +23,17 @@ class AuthorizePacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketAndSNWhenCalledThenReturnAuthorizePacket() { @Test fun getRequestGivenPacketAndSNWhenCalledThenReturnAuthorizePacket() {
// Inputs // Inputs
val opCode = 5 val opCode = 5
val sn = 2859923929 medtrumPump.pumpSN = 2859923929
medtrumPump.patchSessionToken = 667
// Call // Call
val packet = AuthorizePacket(packetInjector, sn) val packet = AuthorizePacket(packetInjector)
val result = packet.getRequest() val result = packet.getRequest()
// Expected values // Expected values
val key = 3364239851 val key = 3364239851
val type = 2 val type = 2
val expectedByteArray = byteArrayOf(opCode.toByte()) + type.toByte() + 0.toByteArray(4) + key.toByteArray(4) val expectedByteArray = byteArrayOf(opCode.toByte()) + type.toByte() + medtrumPump.patchSessionToken.toByteArray(4) + key.toByteArray(4)
assertEquals(10, result.size) assertEquals(10, result.size)
assertEquals(expectedByteArray.contentToString(), result.contentToString()) assertEquals(expectedByteArray.contentToString(), result.contentToString())
} }
@ -47,7 +49,7 @@ class AuthorizePacketTest : MedtrumTestBase() {
// Call // Call
val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + 0.toByte() + deviceType.toByte() + swVerX.toByte() + swVerY.toByte() + swVerZ.toByte() val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + 0.toByte() + deviceType.toByte() + swVerX.toByte() + swVerY.toByte() + swVerZ.toByte()
val packet = AuthorizePacket(packetInjector, 0) val packet = AuthorizePacket(packetInjector)
val result = packet.handleResponse(response) val result = packet.handleResponse(response)
// Expected values // Expected values
@ -65,7 +67,7 @@ class AuthorizePacketTest : MedtrumTestBase() {
// Call // Call
val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2)
val packet = AuthorizePacket(packetInjector, 0) val packet = AuthorizePacket(packetInjector)
packet.opCode = opCode.toByte() packet.opCode = opCode.toByte()
val result = packet.handleResponse(response) val result = packet.handleResponse(response)