Initial TBR implementation and pumpSync for basals etc

This commit is contained in:
jbr7rr 2023-05-20 20:40:55 +02:00
parent 61e873dbcc
commit 0d8f07ad0a
19 changed files with 622 additions and 104 deletions

View file

@ -18,6 +18,7 @@ import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpEnactResult import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.pump.PumpPluginBase import info.nightscout.interfaces.pump.PumpPluginBase
import info.nightscout.interfaces.pump.PumpSync import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.TemporaryBasalStorage
import info.nightscout.interfaces.pump.actions.CustomAction import info.nightscout.interfaces.pump.actions.CustomAction
import info.nightscout.interfaces.pump.actions.CustomActionType import info.nightscout.interfaces.pump.actions.CustomActionType
import info.nightscout.interfaces.pump.defs.ManufacturerType import info.nightscout.interfaces.pump.defs.ManufacturerType
@ -51,6 +52,7 @@ import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.round
@Singleton class MedtrumPlugin @Inject constructor( @Singleton class MedtrumPlugin @Inject constructor(
injector: HasAndroidInjector, injector: HasAndroidInjector,
@ -63,10 +65,11 @@ import javax.inject.Singleton
private val context: Context, private val context: Context,
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val pumpSync: PumpSync,
private val medtrumPump: MedtrumPump, private val medtrumPump: MedtrumPump,
private val uiInteraction: UiInteraction, private val uiInteraction: UiInteraction,
private val profileFunction: ProfileFunction private val profileFunction: ProfileFunction,
private val pumpSync: PumpSync,
private val temporaryBasalStorage: TemporaryBasalStorage
) : PumpPluginBase( ) : PumpPluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.PUMP) .mainType(PluginType.PUMP)
@ -205,7 +208,7 @@ import javax.inject.Singleton
} }
override val baseBasalRate: Double override val baseBasalRate: Double
get() = 0.0 // TODO get() = medtrumPump.baseBasalRate
override val reservoirLevel: Double override val reservoirLevel: Double
get() = medtrumPump.reservoir get() = medtrumPump.reservoir
@ -222,7 +225,24 @@ import javax.inject.Singleton
} }
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult { override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
return PumpEnactResult(injector) // TODO if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute - absoluteRate: $absoluteRate, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
// round rate to 0.05
val pumpRate = round(absoluteRate * 20) / 20 // TODO: Maybe replace by constraints thing
temporaryBasalStorage.add(PumpSync.PumpState.TemporaryBasal(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), pumpRate, true, tbrType, 0L, 0L))
val connectionOk = medtrumService?.setTempBasal(pumpRate, durationInMinutes) ?: false
if (connectionOk
&& medtrumPump.tempBasalInProgress
&& Math.abs(medtrumPump.tempBasalAbsoluteRate - pumpRate) <= 0.05
/*&& Math.abs(medtrumPump.tempBasalRemainingMinutes - durationInMinutes) <= 5*/) {
return PumpEnactResult(injector).success(true).enacted(true).duration(/*medtrumPump.tempBasalRemainingMinutes*/durationInMinutes).absolute(medtrumPump.tempBasalAbsoluteRate).isPercent(false)
.isTempCancel(false)
} else {
aapsLogger.error(LTag.PUMP, "setTempBasalAbsolute failed, connectionOk: $connectionOk, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}, tempBasalAbsoluteRate: ${medtrumPump.tempBasalAbsoluteRate}") //, tempBasalRemainingMinutes: ${medtrumPump.tempBasalRemainingMinutes}")
return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum setTempBasalAbsolute failed")
}
} }
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 {
@ -236,7 +256,16 @@ import javax.inject.Singleton
} }
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
return PumpEnactResult(injector) // TODO if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
aapsLogger.info(LTag.PUMP, "cancelTempBasal - enforceNew: $enforceNew")
val connectionOk = medtrumService?.cancelTempBasal() ?: false
if (connectionOk && !medtrumPump.tempBasalInProgress) {
return PumpEnactResult(injector).success(true).enacted(true).isTempCancel(true)
} else {
aapsLogger.error(LTag.PUMP, "cancelTempBasal failed, connectionOk: $connectionOk, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}")
return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum cancelTempBasal failed")
}
} }
override fun cancelExtendedBolus(): PumpEnactResult { override fun cancelExtendedBolus(): PumpEnactResult {
@ -289,8 +318,4 @@ import javax.inject.Singleton
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) { override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
} }
private fun readTBR(): PumpSync.PumpState.TemporaryBasal? {
return pumpSync.expectedPumpState().temporaryBasal // TODO
}
} }

View file

@ -1,16 +1,22 @@
package info.nightscout.pump.medtrum package info.nightscout.pump.medtrum
import android.util.Base64
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.pump.PumpSync
import info.nightscout.interfaces.pump.TemporaryBasalStorage
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.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.BasalType
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.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 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
@ -21,7 +27,9 @@ 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 pumpSync: PumpSync,
private val temporaryBasalStorage: TemporaryBasalStorage
) { ) {
// Connection state flow // Connection state flow
@ -33,6 +41,14 @@ class MedtrumPump @Inject constructor(
_connectionState.value = value _connectionState.value = value
} }
/** Patch activated state, mainly for UI, but also controls the connection flow,
* if patch is not activated, AAPS cannot connect to the pump, we can then connect trough the activation flow.
* Note: this is also saved in SP, by the set functions
*/
private var _patchActivated = false
val patchActivated: Boolean
get() = _patchActivated
// Pump state flow // Pump state flow
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE) private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
val pumpStateFlow: StateFlow<MedtrumPumpState> = _pumpState val pumpStateFlow: StateFlow<MedtrumPumpState> = _pumpState
@ -42,10 +58,6 @@ class MedtrumPump @Inject constructor(
_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
@ -55,14 +67,62 @@ class MedtrumPump @Inject constructor(
_primeProgress.value = value _primeProgress.value = value
} }
var pumpSN = 0L /** Stuff stored in SP */
val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection private var _patchSessionToken = 0L
var patchSessionToken = 0L var patchSessionToken: Long
get() = _patchSessionToken
set(value) {
_patchSessionToken = value
sp.putLong(R.string.key_session_token, value)
}
private var _patchId = 0L
var patchId: Long
get() = _patchId
set(value) {
_patchId = value
sp.putLong(R.string.key_patch_id, value)
}
private var _currentSequenceNumber = 0
var currentSequenceNumber: Int
get() = _currentSequenceNumber
set(value) {
_currentSequenceNumber = value
sp.putInt(R.string.key_current_sequence_number, value)
}
private var _syncedSequenceNumber = 0
var syncedSequenceNumber: Int
get() = _syncedSequenceNumber
set(value) {
_syncedSequenceNumber = value
sp.putInt(R.string.key_synced_sequence_number, value)
}
private var _actualBasalProfile = byteArrayOf(0)
var actualBasalProfile: ByteArray
get() = _actualBasalProfile
set(value) {
_actualBasalProfile = value
val encodedString = Base64.encodeToString(value, Base64.DEFAULT)
sp.putString(R.string.key_actual_basal_profile, encodedString)
}
private var _lastBasalType: BasalType = BasalType.NONE
var lastBasalType: BasalType
get() = _lastBasalType
set(value) {
_lastBasalType = value
sp.putInt(R.string.key_last_basal_type, value.ordinal)
}
private var _pumpSN = 0L
val pumpSN: Long
get() = _pumpSN
val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection
// 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 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!
@ -77,15 +137,24 @@ class MedtrumPump @Inject constructor(
var alarmParameter = 0 var alarmParameter = 0
// Last basal status update // Last basal status update
var lastBasalType = 0 // TODO: Save this in SP?
var lastBasalRate = 0.0 var lastBasalRate = 0.0
var lastBasalSequence = 0 var lastBasalSequence = 0
var lastBasalPatchId = 0 var lastBasalPatchId = 0L
var lastBasalStartTime = 0L var lastBasalStartTime = 0L
val baseBasalRate: Double
get() = getCurrentHourlyBasalFromMedtrumProfileArray(actualBasalProfile)
// TBR status
val tempBasalInProgress: Boolean
get() = lastBasalType == BasalType.ABSOLUTE_TEMP || lastBasalType == BasalType.RELATIVE_TEMP
val tempBasalAbsoluteRate: Double
get() = if (tempBasalInProgress) lastBasalRate else 0.0
// Last stop status update // Last stop status update
var lastStopSequence = 0 var lastStopSequence = 0
var lastStopPatchId = 0 var lastStopPatchId = 0L
// 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)
@ -94,6 +163,45 @@ class MedtrumPump @Inject constructor(
var desiredHourlyMaxInsulin: Int = 40 var desiredHourlyMaxInsulin: Int = 40
var desiredDailyMaxInsulin: Int = 180 var desiredDailyMaxInsulin: Int = 180
init {
// Load stuff from SP
_patchActivated = sp.getBoolean(R.string.key_patch_activated, false)
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
_patchId = sp.getLong(R.string.key_patch_id, 0L)
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
_lastBasalType = enumValues<BasalType>()[sp.getInt(R.string.key_last_basal_type, 0)]
val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
try {
_actualBasalProfile = Base64.decode(encodedString, Base64.DEFAULT)
} catch (e: Exception) {
aapsLogger.error(LTag.PUMP, "Error decoding basal profile from SP: $encodedString")
}
if (patchActivated) {
aapsLogger.debug(LTag.PUMP, "changePump: Patch is already activated, setting as ACTIVE")
// Set inital status as active will be updated on first connection
pumpState = MedtrumPumpState.ACTIVE
}
loadUserSettingsFromSP()
}
fun loadUserSettingsFromSP() {
// TODO
// desiredPatchExpiration = sp.getBoolean(R.string.key_patch_expiration, false)
// desiredAlarmSetting = sp.getInt(R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code)
// desiredHourlyMaxInsulin = sp.getInt(R.string.key_hourly_max_insulin, 40)
// desiredDailyMaxInsulin = sp.getInt(R.string.key_daily_max_insulin, 180)
try {
_pumpSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
} catch (e: NumberFormatException) {
aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
}
}
fun setPatchActivatedState(activated: Boolean) { fun setPatchActivatedState(activated: Boolean) {
aapsLogger.debug(LTag.PUMP, "setPatchActivatedState: $activated") aapsLogger.debug(LTag.PUMP, "setPatchActivatedState: $activated")
_patchActivated = activated _patchActivated = activated
@ -101,7 +209,8 @@ class MedtrumPump @Inject constructor(
} }
/** When the activation/deactivation screen, and the connection flow needs to be controlled, /** 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 */ * 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) { fun setPatchActivatedStateTemp(activated: Boolean) {
aapsLogger.debug(LTag.PUMP, "setPatchActivatedStateTemp: $activated") aapsLogger.debug(LTag.PUMP, "setPatchActivatedStateTemp: $activated")
_patchActivated = activated _patchActivated = activated
@ -123,29 +232,109 @@ class MedtrumPump @Inject constructor(
return (list.size).toByteArray(1) + basals return (list.size).toByteArray(1) + basals
} }
fun handleBasalStatusUpdate(basalType: Int, basalValue: Double, basalSequence: Int, basalPatchId: Int, basalStartTime: Long) { fun getCurrentHourlyBasalFromMedtrumProfileArray(basalProfile: ByteArray): Double {
val basalCount = basalProfile[0].toInt()
var basal = 0.0
if (basalProfile.size < 4 || (basalProfile.size - 1) % 3 != 0 || basalCount > 24) {
aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: No valid basal profile set")
return basal
}
val hourOfDayMinutes = dateUtil.dateAndTimeString(dateUtil.now()).substring(11, 13).toInt() * 60 + dateUtil.dateAndTimeString(dateUtil.now()).substring(14, 16).toInt()
for (index in 0 until basalCount) {
val currentIndex = 1 + (index * 3)
val nextIndex = currentIndex + 3
val rateAndTime = basalProfile.copyOfRange(currentIndex, nextIndex).toInt()
val rate = (rateAndTime shr 12) * 0.05
val startMinutes = rateAndTime and 0xFFF
val endMinutes = if (nextIndex < basalProfile.size) {
val nextRateAndTime = basalProfile.copyOfRange(nextIndex, nextIndex + 3).toInt()
nextRateAndTime and 0xFFF
} else {
24 * 60
}
if (hourOfDayMinutes in startMinutes until endMinutes) {
basal = rate
aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: basal: $basal")
break
}
aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: rate: $rate, startMinutes: $startMinutes, endMinutes: $endMinutes")
}
return basal
}
fun handleBasalStatusUpdate(basalType: BasalType, basalValue: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long) {
handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now()) handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now())
} }
fun handleBasalStatusUpdate(basalType: Int, basalRate: Double, basalSequence: Int, basalPatchId: Int, basalStartTime: Long, receivedTime: Long) { fun handleBasalStatusUpdate(basalType: BasalType, basalRate: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long, receivedTime: Long) {
aapsLogger.debug( aapsLogger.debug(
LTag.PUMP, "handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + LTag.PUMP,
"receivedTime: $receivedTime" "handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + "receivedTime: $receivedTime"
) )
if (basalType.isTempBasal()) {
// TODO: Is this the correct place to sync temporaryBasalInfo? Note: it will be removed after getting it once, So this would only apply when called in setTempBasalPacket, maybe first check if basal entry already exists and leave this here, then we can also let the onNotification stuff sync basal?
val temporaryBasalInfo = temporaryBasalStorage.findTemporaryBasal(basalStartTime, basalRate)
// If duration is unknown, no way to get it now, set patch lifetime as duration
val duration = temporaryBasalInfo?.duration ?: T.mins(4800).msecs()
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime,
rate = basalRate, // TODO: Support percent here, this will break things? Check if this is correct
duration = duration,
isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
type = temporaryBasalInfo?.type,
pumpId = basalStartTime,
pumpType = pumpType,
pumpSerial = pumpSN.toString(radix = 16)
)
aapsLogger.debug(
LTag.PUMPCOMM,
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " + "Rate: $basalRate Duration: ${duration}min"
)
} else if (basalType.isSuspendedByPump()) {
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime,
rate = 0.0,
duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime,
pumpType = pumpType,
pumpSerial = pumpSN.toString(radix = 16)
)
aapsLogger.debug(
LTag.PUMPCOMM,
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime)"
)
}
// Update medtrum pump state
lastBasalType = basalType lastBasalType = basalType
lastBasalRate = basalRate lastBasalRate = basalRate
lastBasalSequence = basalSequence lastBasalSequence = basalSequence
lastKnownSequenceNumber = basalSequence if (basalSequence > currentSequenceNumber) {
currentSequenceNumber = basalSequence
}
lastBasalPatchId = basalPatchId lastBasalPatchId = basalPatchId
if (basalPatchId != patchId) {
aapsLogger.error(LTag.PUMP, "handleBasalStatusUpdate: WTF? PatchId in status update does not match current patchId!")
}
lastBasalStartTime = basalStartTime lastBasalStartTime = basalStartTime
// TODO Handle history
} }
fun handleStopStatusUpdate(stopSequence: Int, stopPatchId: Int) { fun handleStopStatusUpdate(stopSequence: Int, stopPatchId: Long) {
aapsLogger.debug(LTag.PUMP, "handleStopStatusUpdate: stopSequence: $stopSequence stopPatchId: $stopPatchId") aapsLogger.debug(LTag.PUMP, "handleStopStatusUpdate: stopSequence: $stopSequence stopPatchId: $stopPatchId")
lastStopSequence = stopSequence lastStopSequence = stopSequence
lastKnownSequenceNumber = stopSequence if (stopSequence > currentSequenceNumber) {
currentSequenceNumber = stopSequence
}
lastStopPatchId = stopPatchId lastStopPatchId = stopPatchId
// TODO Handle history if (stopPatchId != patchId) {
aapsLogger.error(LTag.PUMP, "handleStopStatusUpdate: WTF? PatchId in status update does not match current patchId!")
}
} }
} }

View file

@ -0,0 +1,58 @@
package info.nightscout.pump.medtrum.comm.enums
enum class BasalType {
NONE,
STANDARD,
EXERCISE,
HOLIDAY,
PROGRAM_A,
PROGRAM_B,
ABSOLUTE_TEMP,
RELATIVE_TEMP,
PROGRAM_C,
PROGRAM_D,
SICK,
AUTO,
NEW,
SUSPEND_LOW_GLUCOSE,
SUSPEND_PREDICT_LOW_GLUCOSE,
SUSPEND_AUTO,
SUSPEND_MORE_THAN_MAX_PER_HOUR,
SUSPEND_MORE_THAN_MAX_PER_DAY,
SUSPEND_MANUAL,
SUSPEND_KEY_LOST,
STOP_OCCLUSION,
STOP_EXPIRED,
STOP_EMPTY,
STOP_PATCH_FAULT,
STOP_PATCH_FAULT2,
STOP_BASE_FAULT,
STOP_DISCARD,
STOP_BATTERY_EXHAUSTED,
STOP,
PAUSE_INTERRUPT,
PRIME,
AUTO_MODE_START,
AUTO_MODE_EXIT,
AUTO_MODE_TARGET_100,
AUTO_MODE_TARGET_110,
AUTO_MODE_TARGET_120,
AUTO_MODE_BREAKFAST,
AUTO_MODE_LUNCH,
AUTO_MODE_DINNER,
AUTO_MODE_SNACK,
AUTO_MODE_EXERCISE_START,
AUTO_MODE_EXERCISE_EXIT;
fun getValue(): Int {
return ordinal
}
fun isTempBasal(): Boolean {
return this == ABSOLUTE_TEMP || this == RELATIVE_TEMP
}
fun isSuspendedByPump(): Boolean {
return this in SUSPEND_LOW_GLUCOSE..STOP
}
}

View file

@ -5,6 +5,7 @@ import info.nightscout.interfaces.pump.DetailedBolusInfo
import info.nightscout.interfaces.pump.PumpSync 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.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toByteArray import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toByte import info.nightscout.pump.medtrum.extension.toByte
import info.nightscout.interfaces.stats.TddCalculator import info.nightscout.interfaces.stats.TddCalculator
@ -85,15 +86,17 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
val medtrumTimeUtil = MedtrumTimeUtil() val medtrumTimeUtil = MedtrumTimeUtil()
val patchId = data.copyOfRange(RESP_PATCH_ID_START, RESP_PATCH_ID_END).toLong() val patchId = data.copyOfRange(RESP_PATCH_ID_START, RESP_PATCH_ID_END).toLong()
val time = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong()) val time = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt() val basalType = enumValues<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 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 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 basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong()) val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
medtrumPump.patchId = patchId medtrumPump.patchId = patchId
medtrumPump.lastTimeReceivedFromPump = time medtrumPump.lastTimeReceivedFromPump = time
medtrumPump.currentSequenceNumber = basalSequence // We are activated, set the new seq nr
medtrumPump.syncedSequenceNumber = basalSequence // We are activated, reset the synced seq nr ()
// Update the actual basal profile // Update the actual basal profile
medtrumPump.actualBasalProfile = basalProfile medtrumPump.actualBasalProfile = basalProfile
// TODO: Handle history entry // TODO: Handle history entry

View file

@ -3,9 +3,11 @@ 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.CANCEL_TEMP_BASAL import info.nightscout.pump.medtrum.comm.enums.CommandType.CANCEL_TEMP_BASAL
import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toInt import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.rx.logging.LTag
import javax.inject.Inject import javax.inject.Inject
class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) { class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@ -34,11 +36,11 @@ class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(inject
override fun handleResponse(data: ByteArray): Boolean { override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data) val success = super.handleResponse(data)
if (success) { if (success) {
val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt() val basalType = enumValues<BasalType>()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05 val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt() 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 basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong()) val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime) medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
} }

View file

@ -1,16 +1,26 @@
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.PumpSync
import info.nightscout.interfaces.pump.TemporaryBasalStorage
import info.nightscout.pump.medtrum.MedtrumPump import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD
import info.nightscout.pump.medtrum.comm.enums.BasalType
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.pump.medtrum.extension.toLong import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import javax.inject.Inject import javax.inject.Inject
class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int) : MedtrumPacket(injector) { class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int) : MedtrumPacket(injector) {
@Inject lateinit var medtrumPump: MedtrumPump @Inject lateinit var medtrumPump: MedtrumPump
@Inject lateinit var pumpSync: PumpSync
@Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
@Inject lateinit var dateUtil: DateUtil
companion object { companion object {
@ -20,11 +30,29 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
private const val RESP_RECORD_UNKNOWN_END = RESP_RECORD_UNKNOWN_START + 1 private const val RESP_RECORD_UNKNOWN_END = RESP_RECORD_UNKNOWN_START + 1
private const val RESP_RECORD_TYPE_START = RESP_RECORD_UNKNOWN_END private const val RESP_RECORD_TYPE_START = RESP_RECORD_UNKNOWN_END
private const val RESP_RECORD_TYPE_END = RESP_RECORD_TYPE_START + 1 private const val RESP_RECORD_TYPE_END = RESP_RECORD_TYPE_START + 1
private const val RESP_RECORD_SERIAL_START = RESP_RECORD_TYPE_END private const val RESP_RECORD_UNKNOWN1_START = RESP_RECORD_TYPE_END
private const val RESP_RECORD_UNKNOWN1_END = RESP_RECORD_UNKNOWN1_START + 1
private const val RESP_RECORD_SERIAL_START = RESP_RECORD_UNKNOWN1_END
private const val RESP_RECORD_SERIAL_END = RESP_RECORD_SERIAL_START + 4 private const val RESP_RECORD_SERIAL_END = RESP_RECORD_SERIAL_START + 4
private const val RESP_RECORD_PATCHID_START = RESP_RECORD_SERIAL_END private const val RESP_RECORD_PATCHID_START = RESP_RECORD_SERIAL_END
private const val RESP_RECORD_PATCHID_END = RESP_RECORD_PATCHID_START + 2 private const val RESP_RECORD_PATCHID_END = RESP_RECORD_PATCHID_START + 2
private const val RESP_RECORD_DATA_START = RESP_RECORD_PATCHID_END private const val RESP_RECORD_SEQUENCE_START = RESP_RECORD_PATCHID_END
private const val RESP_RECORD_SEQUENCE_END = RESP_RECORD_SEQUENCE_START + 2
private const val RESP_RECORD_DATA_START = RESP_RECORD_SEQUENCE_END
private const val VALID_HEADER = 170
private const val BOLUS_RECORD = 1
private const val BOLUS_RECORD_ALT = 65
private const val BASAL_RECORD = 2
private const val BASAL_RECORD_ALT = 66
private const val ALARM_RECORD = 3
private const val AUTO_RECORD = 4
private const val TIME_SYNC_RECORD = 5
private const val AUTO1_RECORD = 6
private const val AUTO2_RECORD = 7
private const val AUTO3_RECORD = 8
private const val TDD_RECORD = 9
} }
init { init {
@ -44,8 +72,137 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
val recordType = data.copyOfRange(RESP_RECORD_TYPE_START, RESP_RECORD_TYPE_END).toInt() val recordType = data.copyOfRange(RESP_RECORD_TYPE_START, RESP_RECORD_TYPE_END).toInt()
val recordSerial = data.copyOfRange(RESP_RECORD_SERIAL_START, RESP_RECORD_SERIAL_END).toLong() val recordSerial = data.copyOfRange(RESP_RECORD_SERIAL_START, RESP_RECORD_SERIAL_END).toLong()
val recordPatchId = data.copyOfRange(RESP_RECORD_PATCHID_START, RESP_RECORD_PATCHID_END).toInt() val recordPatchId = data.copyOfRange(RESP_RECORD_PATCHID_START, RESP_RECORD_PATCHID_END).toInt()
val recordSequence = data.copyOfRange(RESP_RECORD_SEQUENCE_START, RESP_RECORD_SEQUENCE_END).toInt()
// TODO Handle history records aapsLogger.debug(
LTag.PUMPCOMM,
"GetRecordPacket HandleResponse: Record header: $recordHeader, unknown: $recordUnknown, type: $recordType, serial: $recordSerial, patchId: $recordPatchId, " + "sequence: $recordSequence"
)
medtrumPump.syncedSequenceNumber = recordSequence // Assume sync upwards
if (recordHeader == VALID_HEADER) {
when (recordType) {
BOLUS_RECORD, BOLUS_RECORD_ALT -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD")
}
BASAL_RECORD, BASAL_RECORD_ALT -> {
val medtrumTimeUtil = MedtrumTimeUtil()
val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START, RESP_RECORD_DATA_START + 4).toLong())
val basalEndTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START + 4, RESP_RECORD_DATA_START + 8).toLong())
val basalType = enumValues<BasalType>()[data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 9).toInt()]
val basalEndReason = data.copyOfRange(RESP_RECORD_DATA_START + 9, RESP_RECORD_DATA_START + 10).toInt()
val basalRate = data.copyOfRange(RESP_RECORD_DATA_START + 10, RESP_RECORD_DATA_START + 12).toInt() * 0.05
val basalDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 14).toInt() * 0.05
val basalPercent = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toInt()
aapsLogger.debug(
LTag.PUMPCOMM,
"GetRecordPacket HandleResponse: BASAL_RECORD: Start: $basalStartTime, End: $basalEndTime, Type: $basalType, EndReason: $basalEndReason, Rate: $basalRate, Delivered: $basalDelivered, Percent: $basalPercent"
)
when (basalType) {
BasalType.STANDARD -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Standard basal")
// If we are here it means the basal has ended
}
BasalType.ABSOLUTE_TEMP, BasalType.RELATIVE_TEMP -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Absolute temp basal")
val duration = (basalEndTime - basalStartTime)
if (duration > 0) { // Sync start and end
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime,
rate = if (basalType == BasalType.ABSOLUTE_TEMP) basalRate else basalPercent.toDouble(),
duration = duration,
isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
type = PumpSync.TemporaryBasalType.NORMAL,
pumpId = basalStartTime,
pumpType = medtrumPump.pumpType,
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
LTag.PUMPCOMM,
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_SYNC: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
"Rate: $basalRate Duration: ${duration}min"
)
} else { // Sync only end ?
pumpSync.syncStopTemporaryBasalWithPumpId(
timestamp = basalEndTime,
endPumpId = basalEndTime,
pumpType = medtrumPump.pumpType,
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.warn(
LTag.PUMPCOMM,
"handleBasalStatusUpdate from record: EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalEndTime)} ($basalEndTime) " + "Rate: $basalRate Duration: ${duration}min"
)
}
}
in BasalType.SUSPEND_LOW_GLUCOSE..BasalType.STOP -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Suspend basal")
val duration = (basalEndTime - basalStartTime)
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalEndTime,
rate = 0.0,
duration = duration,
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime,
pumpType = medtrumPump.pumpType,
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
LTag.PUMPCOMM,
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT SUSPEND: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
"Rate: $basalRate Duration: ${duration}min"
)
}
else -> {
aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Unknown basal type: $basalType")
// TODO: Error warning
}
}
}
ALARM_RECORD -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: ALARM_RECORD")
}
AUTO_RECORD -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO_RECORD")
}
TIME_SYNC_RECORD -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: TIME_SYNC_RECORD")
}
AUTO1_RECORD -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO1_RECORD")
}
AUTO2_RECORD -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO2_RECORD")
}
AUTO3_RECORD -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO3_RECORD")
}
TDD_RECORD -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: TDD_RECORD")
}
else -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: Unknown record type: $recordType")
}
}
} else {
aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: Invalid record header")
}
} }
return success return success

View file

@ -25,7 +25,7 @@ class GetTimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
override fun handleResponse(data: ByteArray): Boolean { override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data) val success = super.handleResponse(data)
if (success) { if (success) {
val time = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong()) val time = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
medtrumPump.lastTimeReceivedFromPump = time medtrumPump.lastTimeReceivedFromPump = time
} }

View file

@ -2,6 +2,7 @@ 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.BasalType
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
@ -98,7 +99,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
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 // TODO: Check for other flags here :) 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
@ -115,18 +116,20 @@ 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).toInt() val basalType = enumValues<BasalType>()[data.copyOfRange(offset, offset + 1).toInt()]
var basalSequence = data.copyOfRange(offset + 1, offset + 3).toInt() var basalSequence = data.copyOfRange(offset + 1, offset + 3).toInt()
var basalPatchId = data.copyOfRange(offset + 3, offset + 5).toInt() var basalPatchId = data.copyOfRange(offset + 3, offset + 5).toLong()
var basalInterval = data.copyOfRange(offset + 5, offset + 9).toInt() var basalTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset + 5, offset + 9).toLong())
var basalRateAndDelivery = data.copyOfRange(offset + 9, offset + 12).toInt() var basalRateAndDelivery = data.copyOfRange(offset + 9, offset + 12).toInt()
var basalRate = (basalRateAndDelivery and 0xFFF) * 0.05 var basalRate = (basalRateAndDelivery and 0xFFF) * 0.05
var basalDelivery = (basalRateAndDelivery shr 12) * 0.05 var basalDelivery = (basalRateAndDelivery shr 12) * 0.05
aapsLogger.debug( aapsLogger.debug(
LTag.PUMPCOMM, LTag.PUMPCOMM,
"Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal interval: $basalInterval, basal rate: $basalRate, basal delivery: $basalDelivery" "Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal time: $basalTime, basal rate: $basalRate, basal delivery: $basalDelivery"
) )
// TODO Sync basal flow // TODO: Check if basal is known, if not add it
// medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalTime)
// TODO: Handle basal delivery
offset += 12 offset += 12
} }
@ -165,9 +168,16 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_STORAGE != 0) { if (fieldMask and MASK_STORAGE != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Storage notification received") aapsLogger.debug(LTag.PUMPCOMM, "Storage notification received")
// TODO, trigger check for new sequence? // TODO, trigger check for new sequence?
medtrumPump.lastKnownSequenceNumber = data.copyOfRange(offset, offset + 2).toInt() val sequence = data.copyOfRange(offset, offset + 2).toInt()
medtrumPump.patchId = data.copyOfRange(offset + 2, offset + 4).toLong() if (sequence > medtrumPump.currentSequenceNumber) {
aapsLogger.debug(LTag.PUMPCOMM, "Last known sequence number: ${medtrumPump.lastKnownSequenceNumber}, patch id: ${medtrumPump.patchId}") medtrumPump.currentSequenceNumber = sequence
}
val patchId = data.copyOfRange(offset + 2, offset + 4).toLong()
if (patchId != medtrumPump.patchId) {
aapsLogger.error(LTag.PUMPCOMM, "handleMaskedMessage: WTF? We got wrong patch id!")
// TODO: We should terminate session or stop patch here? or at least throw error? THis can be thrown during activation process though
}
aapsLogger.debug(LTag.PUMPCOMM, "Last known sequence number: ${medtrumPump.currentSequenceNumber}, patch id: ${patchId}")
offset += 4 offset += 4
} }
@ -182,7 +192,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_START_TIME != 0) { if (fieldMask and MASK_START_TIME != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Start time notification received") aapsLogger.debug(LTag.PUMPCOMM, "Start time notification received")
medtrumPump.patchStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(offset, offset + 4).toLong()) medtrumPump.patchStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset, offset + 4).toLong())
aapsLogger.debug(LTag.PUMPCOMM, "Patch start time: ${medtrumPump.patchStartTime}") aapsLogger.debug(LTag.PUMPCOMM, "Patch start time: ${medtrumPump.patchStartTime}")
offset += 4 offset += 4
} }

View file

@ -3,6 +3,7 @@ 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.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toInt import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
@ -41,11 +42,11 @@ class SetBasalProfilePacket(injector: HasAndroidInjector, private val basalProfi
val success = super.handleResponse(data) val success = super.handleResponse(data)
if (success) { if (success) {
val medtrumTimeUtil = MedtrumTimeUtil() val medtrumTimeUtil = MedtrumTimeUtil()
val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt() val basalType = enumValues<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 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 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 basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong()) val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
// Update the actual basal profile // Update the actual basal profile
medtrumPump.actualBasalProfile = basalProfile medtrumPump.actualBasalProfile = basalProfile

View file

@ -3,10 +3,12 @@ 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_TEMP_BASAL import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_TEMP_BASAL
import info.nightscout.pump.medtrum.comm.enums.BasalType
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.pump.medtrum.extension.toLong import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.rx.logging.LTag
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.round import kotlin.math.round
@ -49,11 +51,19 @@ class SetTempBasalPacket(injector: HasAndroidInjector, private val absoluteRate:
override fun handleResponse(data: ByteArray): Boolean { override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data) val success = super.handleResponse(data)
if (success) { if (success) {
val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt() val basalType = enumValues<BasalType>()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05 val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt() 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 basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
val rawTime = data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong()
val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
aapsLogger.debug(LTag.PUMPCOMM, "Basal status update: type=$basalType, rate=$basalRate, sequence=$basalSequence, patchId=$basalPatchId, startTime=$basalStartTime, rawTime=$rawTime")
// TODO: For debugging remove later
val pumpTime = MedtrumTimeUtil().getCurrentTimePumpSeconds()
val systemTime = System.currentTimeMillis()
aapsLogger.debug(LTag.PUMPCOMM, "Pump time: $pumpTime, System time: $systemTime")
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime) medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
} }

View file

@ -4,6 +4,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.extension.toInt import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.comm.enums.CommandType.STOP_PATCH import info.nightscout.pump.medtrum.comm.enums.CommandType.STOP_PATCH
import info.nightscout.pump.medtrum.extension.toLong
import javax.inject.Inject import javax.inject.Inject
class StopPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) { class StopPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@ -27,7 +28,7 @@ class StopPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
val success = super.handleResponse(data) val success = super.handleResponse(data)
if (success) { if (success) {
val stopSequence = data.copyOfRange(RESP_STOP_SEQUENCE_START, RESP_STOP_SEQUENCE_END).toInt() val stopSequence = data.copyOfRange(RESP_STOP_SEQUENCE_START, RESP_STOP_SEQUENCE_END).toInt()
val stopPatchId = data.copyOfRange(RESP_STOP_PATCH_ID_START, RESP_STOP_PATCH_ID_END).toInt() val stopPatchId = data.copyOfRange(RESP_STOP_PATCH_ID_START, RESP_STOP_PATCH_ID_END).toLong()
medtrumPump.handleStopStatusUpdate(stopSequence, stopPatchId) medtrumPump.handleStopStatusUpdate(stopSequence, stopPatchId)
} }

View file

@ -116,8 +116,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
} }
fun startPrime(): Boolean { fun startPrime(): Boolean {
val packet = PrimePacket(injector) return sendPacketAndGetResponse(PrimePacket(injector))
return sendPacketAndGetResponse(packet)
} }
fun startActivate(): Boolean { fun startActivate(): Boolean {
@ -141,18 +140,19 @@ class MedtrumService : DaggerService(), BLECommCallback {
} }
fun readPumpStatus() { fun readPumpStatus() {
// TODO read pump history // TODO decide what we need to do here
} var result = false
fun loadEvents(): PumpEnactResult { // Most of these things are already done when a connection is setup, but wo dont know how long the pump was connected for?
if (!medtrumPlugin.isInitialized()) { // So just do a syncronize to make sure we have the latest data
val result = PumpEnactResult(injector).success(false) result = sendPacketAndGetResponse(SynchronizePacket(injector))
result.comment = "pump not initialized"
return result // Sync records (based on the info we have from the sync)
if (result) result = syncRecords()
if (!result) {
aapsLogger.error(LTag.PUMPCOMM, "Failed to sync records")
return
} }
// 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 {
@ -165,24 +165,59 @@ class MedtrumService : DaggerService(), BLECommCallback {
// TODO // TODO
} }
fun setTempBasal(absoluteRate: Double, durationInMinutes: Int): Boolean {
var result = true
if (medtrumPump.tempBasalInProgress) {
result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
}
if (result) result = sendPacketAndGetResponse(SetTempBasalPacket(injector, absoluteRate, durationInMinutes))
// Get history records, this will update the pump state
if (result) result = syncRecords()
return result
}
fun cancelTempBasal(): Boolean {
var result = false
result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
// Get history records, this will update the pump state
if (result) result = syncRecords()
return result
}
fun updateBasalsInPump(profile: Profile): Boolean { fun updateBasalsInPump(profile: Profile): Boolean {
var result = false
val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) } val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
return packet?.let { sendPacketAndGetResponse(it) } == true result = packet?.let { sendPacketAndGetResponse(it) } == true
// TODO: We might want to get rid of this and cancel the TBR before we set the basal profile
// Update basal affects the TBR records (the pump will cancel the TBR, set our basal profile, and resume the TBR in a new record)
// Get history records, this will update the pump state and add changes in TBR to AAPS history
if (result) result = syncRecords()
return result
} }
fun changePump() { fun changePump() {
aapsLogger.debug(LTag.PUMP, "changePump: called!") aapsLogger.debug(LTag.PUMP, "changePump: called!")
try { medtrumPump.loadUserSettingsFromSP()
medtrumPump.pumpSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16) }
} catch (e: NumberFormatException) {
aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!") /** This gets the history records from the pump */
} private fun syncRecords(): Boolean {
medtrumPump.setPatchActivatedState(sp.getBoolean(R.string.key_patch_activated, false)) aapsLogger.debug(LTag.PUMP, "syncRecords: called!, syncedSequenceNumber: ${medtrumPump.syncedSequenceNumber}, currentSequenceNumber: ${medtrumPump.currentSequenceNumber}")
medtrumPump.patchSessionToken = sp.getLong(R.string.key_session_token, 0) var result = false
if (medtrumPump.patchActivated) { // TODO: Check if we need to sync older records as well
aapsLogger.debug(LTag.PUMP, "changePump: Patch is already activated, setting as ACTIVE") // Note: medtrum app fetches all records when they sync?
medtrumPump.pumpState = MedtrumPumpState.ACTIVE // Set inital status as active will be updated on first connection for (sequence in medtrumPump.syncedSequenceNumber..medtrumPump.currentSequenceNumber) {
result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
if (!result) break
} }
return result
} }
/** BLECommCallbacks */ /** BLECommCallbacks */
@ -206,7 +241,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onSendMessageError(reason: String) { override fun onSendMessageError(reason: String) {
aapsLogger.debug(LTag.PUMPCOMM, "<<<<< error during send message $reason") aapsLogger.debug(LTag.PUMPCOMM, "<<<<< error during send message $reason")
// TODO currentState.onSendMessageError(reason)
} }
/** Service stuff */ /** Service stuff */
@ -270,6 +305,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
open fun waitForResponse(): Boolean { open fun waitForResponse(): Boolean {
return false return false
} }
open fun onSendMessageError(reason: String) {
aapsLogger.debug(LTag.PUMPCOMM, "onSendMessageError: " + this.toString() + "reason: $reason")
}
} }
private inner class IdleState : State() { private inner class IdleState : State() {
@ -350,16 +389,18 @@ 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!
val currTimeSec = dateUtil.nowWithoutMilliseconds() / 1000 val currTime = dateUtil.nowWithoutMilliseconds()
if (abs(timeUtil.convertPumpTimeToSystemTimeSeconds(medtrumPump.lastTimeReceivedFromPump) - currTimeSec) <= 5) { // Allow 5 sec deviation if (abs(medtrumPump.lastTimeReceivedFromPump - currTime) <= T.secs(5).msecs()) { // Allow 5 sec deviation
toState(SynchronizeState()) toState(SynchronizeState())
} else { } else {
aapsLogger.debug( aapsLogger.debug(
LTag.PUMPCOMM, LTag.PUMPCOMM,
"GetTimeState.onIndication need to set time. systemTime: $currTimeSec PumpTime: ${medtrumPump.lastTimeReceivedFromPump} Pump Time to system time: " + timeUtil.convertPumpTimeToSystemTimeSeconds( "GetTimeState.onIndication need to set time. systemTime: $currTime PumpTime: ${medtrumPump.lastTimeReceivedFromPump} Pump Time to system time: " + timeUtil
.convertPumpTimeToSystemTimeMillis(
medtrumPump.lastTimeReceivedFromPump medtrumPump.lastTimeReceivedFromPump
) )
) )
// TODO: Setting time cancels any TBR, so we need to handle that and cancel? or let AAPS handle time syncs?
toState(SetTimeState()) toState(SetTimeState())
} }
} else if (mPacket?.failed == true) { } else if (mPacket?.failed == true) {
@ -497,6 +538,12 @@ class MedtrumService : DaggerService(), BLECommCallback {
responseSuccess = false responseSuccess = false
} }
override fun onSendMessageError(reason: String) {
super.onSendMessageError(reason)
responseHandled = true
responseSuccess = false
}
override fun waitForResponse(): Boolean { override fun waitForResponse(): Boolean {
val startTime = System.currentTimeMillis() val startTime = System.currentTimeMillis()
val timeoutMillis = T.secs(45).msecs() val timeoutMillis = T.secs(45).msecs()

View file

@ -46,9 +46,9 @@ class MedtrumOverviewFragment : MedtrumBaseFragment<FragmentMedtrumOverviewBindi
EventType.ACTIVATION_CLICKED -> requireContext().apply { EventType.ACTIVATION_CLICKED -> requireContext().apply {
val step = convertToPatchStep(medtrumPump.pumpState) val step = convertToPatchStep(medtrumPump.pumpState)
// TODO is stil needed? // 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))
} }

View file

@ -174,7 +174,6 @@ class MedtrumViewModel @Inject constructor(
// New session, generate new session token // New session, generate new session token
aapsLogger.info(LTag.PUMP, "preparePatch: new session") aapsLogger.info(LTag.PUMP, "preparePatch: new session")
medtrumPump.patchSessionToken = Crypt().generateRandomToken() medtrumPump.patchSessionToken = Crypt().generateRandomToken()
sp.putLong(R.string.key_session_token, medtrumPump.patchSessionToken)
// Connect to pump // Connect to pump
medtrumService?.connect("PreparePatch") medtrumService?.connect("PreparePatch")
} }

View file

@ -11,10 +11,16 @@ class MedtrumTimeUtil {
return Duration.between(startInstant, currentInstant).seconds return Duration.between(startInstant, currentInstant).seconds
} }
fun convertPumpTimeToSystemTimeSeconds(pumpTime: Long) : Long { fun getCurrentTimePumpMillis() : Long {
val startInstant = Instant.parse("2014-01-01T00:00:00Z")
val currentInstant = Instant.now()
return Duration.between(startInstant, currentInstant).seconds * 1000
}
fun convertPumpTimeToSystemTimeMillis(pumpTime: Long) : Long {
val startInstant = Instant.parse("2014-01-01T00:00:00Z") val startInstant = Instant.parse("2014-01-01T00:00:00Z")
val pumpInstant = startInstant.plusSeconds(pumpTime) val pumpInstant = startInstant.plusSeconds(pumpTime)
val epochInstant = Instant.EPOCH val epochInstant = Instant.EPOCH
return Duration.between(epochInstant, pumpInstant).seconds return Duration.between(epochInstant, pumpInstant).seconds * 1000
} }
} }

View file

@ -1,10 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<!-- 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_patch_activated" translatable="false">medtrum_patch_activated</string>
<string name="key_session_token" translatable="false">medtrum_session_token</string> <string name="key_session_token" translatable="false">medtrum_session_token</string>
<string name="key_patch_id" translatable="false">patch_id</string>
<string name="key_actual_basal_profile" translatable="false">actual_basal_profile</string>
<string name="key_last_basal_type" translatable="false">last_basal_type</string>
<string name="key_current_sequence_number" translatable="false">current_sequence_number</string>
<string name="key_synced_sequence_number" translatable="false">synced_sequence_number</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>

View file

@ -4,6 +4,7 @@ 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.pump.PumpSync
import info.nightscout.interfaces.pump.TemporaryBasalStorage
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
@ -14,11 +15,12 @@ open class MedtrumTestBase: TestBaseWithProfile() {
@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 @Mock lateinit var pumpSync: PumpSync
@Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage
lateinit var medtrumPump: MedtrumPump lateinit var medtrumPump: MedtrumPump
@BeforeEach @BeforeEach
fun setup() { fun setup() {
medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil) medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil, pumpSync, temporaryBasalStorage)
} }
} }

View file

@ -2,6 +2,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.MedtrumTestBase import info.nightscout.pump.medtrum.MedtrumTestBase
import info.nightscout.pump.medtrum.extension.toByteArray import info.nightscout.pump.medtrum.extension.toByteArray
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -23,7 +24,9 @@ class AuthorizePacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketAndSNWhenCalledThenReturnAuthorizePacket() { @Test fun getRequestGivenPacketAndSNWhenCalledThenReturnAuthorizePacket() {
// Inputs // Inputs
val opCode = 5 val opCode = 5
medtrumPump.pumpSN = 2859923929 val _pumpSN = MedtrumPump::class.java.getDeclaredField("_pumpSN")
_pumpSN.isAccessible = true
_pumpSN.setLong(medtrumPump, 2859923929)
medtrumPump.patchSessionToken = 667 medtrumPump.patchSessionToken = 667
// Call // Call

View file

@ -48,7 +48,7 @@ class GetTimePacketTest : MedtrumTestBase() {
// Expected values // Expected values
assertEquals(true, result) assertEquals(true, result)
assertEquals(false, packet.failed) assertEquals(false, packet.failed)
assertEquals(MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(time), medtrumPump.lastTimeReceivedFromPump) assertEquals(MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(time), medtrumPump.lastTimeReceivedFromPump)
} }
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() { @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {