diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt index 6b7fe84598..2d154856c5 100644 --- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt +++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt @@ -236,8 +236,8 @@ import kotlin.math.round result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep result.bolusDelivered = t.insulin if (!result.success) { - // Todo error code? - result.comment = "error" + // Note: There are no error codes + result.comment = "failed" } else { result.comment = "ok" } @@ -266,8 +266,8 @@ import kotlin.math.round 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 + // round rate to pump rate + val pumpRate = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value() 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 @@ -307,7 +307,7 @@ import kotlin.math.round } override fun cancelExtendedBolus(): PumpEnactResult { - return PumpEnactResult(injector) // TODO + return PumpEnactResult(injector) } override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject { @@ -333,10 +333,10 @@ import kotlin.math.round return ""// TODO } - override val isFakingTempsByExtendedBoluses: Boolean = false //TODO + override val isFakingTempsByExtendedBoluses: Boolean = false override fun loadTDDs(): PumpEnactResult { - return PumpEnactResult(injector) // TODO + return PumpEnactResult(injector) // Note: Can implement this if we implement history fully (no priority) } override fun canHandleDST(): Boolean { diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt index 086d54be39..330bbdaaef 100644 --- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt +++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt @@ -66,7 +66,15 @@ class MedtrumPump @Inject constructor( set(value) { _primeProgress.value = value } - + + private var _lastBasalType: MutableStateFlow = MutableStateFlow(BasalType.NONE) + val lastBasalTypeFlow: StateFlow = _lastBasalType + var lastBasalType: BasalType + get() = _lastBasalType.value + set(value) { + _lastBasalType.value = value + } + private val _lastBasalRate = MutableStateFlow(0.0) val lastBasalRateFlow: StateFlow = _lastBasalRate var lastBasalRate: Double @@ -125,15 +133,6 @@ class MedtrumPump @Inject constructor( sp.putString(R.string.key_actual_basal_profile, encodedString?: "") } - private var _lastBasalType: MutableStateFlow = MutableStateFlow(BasalType.NONE) - val lastBasalTypeFlow: StateFlow = _lastBasalType - var lastBasalType: BasalType - get() = _lastBasalType.value - set(value) { - _lastBasalType.value = value - sp.putInt(R.string.key_last_basal_type, value.ordinal) // TODO is this still needed in SP? - } - private var _pumpSN = 0L val pumpSN: Long get() = _pumpSN @@ -161,8 +160,6 @@ class MedtrumPump @Inject constructor( var bolusDone = false // success end // Last basal status update - // TODO: Save this in SP? - var lastBasalSequence = 0 var lastBasalPatchId = 0L var lastBasalStartTime = 0L @@ -194,7 +191,6 @@ class MedtrumPump @Inject constructor( _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()[sp.getInt(R.string.key_last_basal_type, 0)] // TODO: is this nice? val encodedString = sp.getString(R.string.key_actual_basal_profile, "0") try { diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt index 907cbeadec..91facb8a59 100644 --- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt +++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt @@ -41,6 +41,11 @@ import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.T import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch import java.util.* import javax.inject.Inject import kotlin.math.abs @@ -74,6 +79,8 @@ class MedtrumService : DaggerService(), BLECommCallback { private var currentState: State = IdleState() private var mPacket: MedtrumPacket? = null + + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) val isConnected: Boolean get() = medtrumPump.connectionState == ConnectionState.CONNECTED @@ -100,8 +107,9 @@ class MedtrumService : DaggerService(), BLECommCallback { } override fun onDestroy() { - disposable.clear() super.onDestroy() + disposable.clear() + scope.cancel() } fun connect(from: String): Boolean { @@ -141,12 +149,9 @@ class MedtrumService : DaggerService(), BLECommCallback { } fun readPumpStatus() { - // TODO decide what we need to do here - var result = false - // Most of these things are already done when a connection is setup, but wo dont know how long the pump was connected for? // So just do a syncronize to make sure we have the latest data - result = sendPacketAndGetResponse(SynchronizePacket(injector)) + var result = sendPacketAndGetResponse(SynchronizePacket(injector)) // Sync records (based on the info we have from the sync) if (result) result = syncRecords() @@ -224,9 +229,7 @@ class MedtrumService : DaggerService(), BLECommCallback { } fun cancelTempBasal(): Boolean { - var result = false - - result = sendPacketAndGetResponse(CancelTempBasalPacket(injector)) + var result = sendPacketAndGetResponse(CancelTempBasalPacket(injector)) // Get history records, this will update the pump state if (result) result = syncRecords() @@ -330,6 +333,9 @@ class MedtrumService : DaggerService(), BLECommCallback { // State class, Can we move this to different file? private abstract inner class State { + protected var responseHandled = false + protected var responseSuccess = false + open fun onEnter() {} open fun onIndication(data: ByteArray) { aapsLogger.debug(LTag.PUMPCOMM, "onIndication: " + this.toString() + "Should not be called here!") @@ -339,22 +345,39 @@ class MedtrumService : DaggerService(), BLECommCallback { aapsLogger.debug(LTag.PUMPCOMM, "onConnected") } - open fun onDisconnected() { + fun onDisconnected() { aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected") medtrumPump.connectionState = ConnectionState.DISCONNECTED if (medtrumPump.patchActivated) { rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED)) } - // TODO: Check flow for this + responseHandled = true + responseSuccess = false toState(IdleState()) } - open fun waitForResponse(): Boolean { - return false + fun waitForResponse(): Boolean { + val startTime = System.currentTimeMillis() + val timeoutMillis = T.secs(45).msecs() + while (!responseHandled) { + if (System.currentTimeMillis() - startTime > timeoutMillis) { + // If we haven't received a response in the specified time, assume the command failed + aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service State timeout") + // Disconnect to cancel any outstanding commands and go back to ready state + bleComm.disconnect("Timeout") + toState(IdleState()) + return false + } + SystemClock.sleep(100) + } + aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service State responseHandled: $responseHandled responseSuccess: $responseSuccess") + return responseSuccess } - open fun onSendMessageError(reason: String) { + fun onSendMessageError(reason: String) { aapsLogger.debug(LTag.PUMPCOMM, "onSendMessageError: " + this.toString() + "reason: $reason") + responseHandled = true + responseSuccess = false } } @@ -368,13 +391,9 @@ class MedtrumService : DaggerService(), BLECommCallback { super.onConnected() toState(AuthState()) } - - override fun onDisconnected() { - super.onDisconnected() - } } - // State for connect flow, could be replaced by commandState and steps in connect() + // State for connect flow private inner class AuthState : State() { val retryCounter = 0 @@ -382,11 +401,16 @@ class MedtrumService : DaggerService(), BLECommCallback { aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached AuthState") mPacket = AuthorizePacket(injector) mPacket?.getRequest()?.let { bleComm.sendMessage(it) } + scope.launch { + waitForResponse() + } } override fun onIndication(data: ByteArray) { if (mPacket?.handleResponse(data) == true) { // Succes! + responseHandled = true + responseSuccess = true // TODO Get pump version info val deviceType = (mPacket as AuthorizePacket).deviceType val swVersion = (mPacket as AuthorizePacket).swVersion @@ -394,31 +418,31 @@ class MedtrumService : DaggerService(), BLECommCallback { toState(GetDeviceTypeState()) } else if (mPacket?.failed == true) { // Failure - // retry twice - // TODO: Test and see if this can be removed - if (retryCounter < 2) { - aapsLogger.error(LTag.PUMPCOMM, "AuthState failed!, retrying") - mPacket?.getRequest()?.let { bleComm.sendMessage(it) } - } else { - bleComm.disconnect("Failure") - toState(IdleState()) - } + responseHandled = true + responseSuccess = false + bleComm.disconnect("Failure") + toState(IdleState()) } } } - // State for connect flow, could be replaced by commandState and steps in connect() + // State for connect flow private inner class GetDeviceTypeState : State() { override fun onEnter() { aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached GetDeviceTypeState") mPacket = GetDeviceTypePacket(injector) mPacket?.getRequest()?.let { bleComm.sendMessage(it) } + scope.launch { + waitForResponse() + } } override fun onIndication(data: ByteArray) { if (mPacket?.handleResponse(data) == true) { // Succes! + responseHandled = true + responseSuccess = true // TODO Get device type and SN val deviceType = (mPacket as GetDeviceTypePacket).deviceType val deviceSN = (mPacket as GetDeviceTypePacket).deviceSN @@ -426,24 +450,31 @@ class MedtrumService : DaggerService(), BLECommCallback { toState(GetTimeState()) } else if (mPacket?.failed == true) { // Failure + responseHandled = true + responseSuccess = false bleComm.disconnect("Failure") toState(IdleState()) } } } - // State for connect flow, could be replaced by commandState and steps in connect() + // State for connect flow private inner class GetTimeState : State() { override fun onEnter() { aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached GetTimeState") mPacket = GetTimePacket(injector) mPacket?.getRequest()?.let { bleComm.sendMessage(it) } + scope.launch { + waitForResponse() + } } override fun onIndication(data: ByteArray) { if (mPacket?.handleResponse(data) == true) { // Succes! + responseHandled = true + responseSuccess = true val currTime = dateUtil.nowWithoutMilliseconds() if (abs(medtrumPump.lastTimeReceivedFromPump - currTime) <= T.secs(5).msecs()) { // Allow 5 sec deviation toState(SynchronizeState()) @@ -460,90 +491,120 @@ class MedtrumService : DaggerService(), BLECommCallback { } } else if (mPacket?.failed == true) { // Failure + responseHandled = true + responseSuccess = false bleComm.disconnect("Failure") toState(IdleState()) } } } - // State for connect flow, could be replaced by commandState and steps in connect() + // State for connect flow private inner class SetTimeState : State() { override fun onEnter() { aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SetTimeState") mPacket = SetTimePacket(injector) mPacket?.getRequest()?.let { bleComm.sendMessage(it) } + scope.launch { + waitForResponse() + } } override fun onIndication(data: ByteArray) { if (mPacket?.handleResponse(data) == true) { // Succes! + responseHandled = true + responseSuccess = true toState(SetTimeZoneState()) } else if (mPacket?.failed == true) { // Failure + responseHandled = true + responseSuccess = false bleComm.disconnect("Failure") toState(IdleState()) } } } - // State for connect flow, could be replaced by commandState and steps in connect() + // State for connect flow private inner class SetTimeZoneState : State() { override fun onEnter() { aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SetTimeZoneState") mPacket = SetTimeZonePacket(injector) mPacket?.getRequest()?.let { bleComm.sendMessage(it) } + scope.launch { + waitForResponse() + } } override fun onIndication(data: ByteArray) { if (mPacket?.handleResponse(data) == true) { // Succes! + responseHandled = true + responseSuccess = true toState(SynchronizeState()) } else if (mPacket?.failed == true) { // Failure + responseHandled = true + responseSuccess = false bleComm.disconnect("Failure") toState(IdleState()) } } } - // State for connect flow, could be replaced by commandState and steps in connect() + // State for connect flow private inner class SynchronizeState : State() { override fun onEnter() { aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SynchronizeState") mPacket = SynchronizePacket(injector) mPacket?.getRequest()?.let { bleComm.sendMessage(it) } + scope.launch { + waitForResponse() + } } override fun onIndication(data: ByteArray) { if (mPacket?.handleResponse(data) == true) { // Succes! + responseHandled = true + responseSuccess = true toState(SubscribeState()) } else if (mPacket?.failed == true) { // Failure + responseHandled = true + responseSuccess = false bleComm.disconnect("Failure") toState(IdleState()) } } } - // State for connect flow, could be replaced by commandState and steps in connect() + // State for connect flow private inner class SubscribeState : State() { override fun onEnter() { aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SubscribeState") mPacket = SubscribePacket(injector) mPacket?.getRequest()?.let { bleComm.sendMessage(it) } + scope.launch { + waitForResponse() + } } override fun onIndication(data: ByteArray) { if (mPacket?.handleResponse(data) == true) { // Succes! + responseHandled = true + responseSuccess = true toState(ReadyState()) } else if (mPacket?.failed == true) { // Failure + responseHandled = true + responseSuccess = false bleComm.disconnect("Failure") toState(IdleState()) } @@ -566,9 +627,6 @@ class MedtrumService : DaggerService(), BLECommCallback { // This state is when a command is send and we wait for a response for that command private inner class CommandState : State() { - private var responseHandled = false - private var responseSuccess = false - override fun onEnter() { aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached CommandState") } @@ -586,34 +644,5 @@ class MedtrumService : DaggerService(), BLECommCallback { toState(ReadyState()) } } - - override fun onDisconnected() { - super.onDisconnected() - responseHandled = true - responseSuccess = false - } - - override fun onSendMessageError(reason: String) { - super.onSendMessageError(reason) - responseHandled = true - responseSuccess = false - } - - override fun waitForResponse(): Boolean { - val startTime = System.currentTimeMillis() - val timeoutMillis = T.secs(45).msecs() - while (!responseHandled) { - if (System.currentTimeMillis() - startTime > timeoutMillis) { - // If we haven't received a response in the specified time, assume the command failed - aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service CommandState timeout") - // Disconnect to cancel any outstanding commands and go back to ready state - bleComm.disconnect("Timeout") - toState(ReadyState()) - return false - } - Thread.sleep(100) - } - return responseSuccess - } } } diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml index ef2b5de75e..dd2665e7b2 100644 --- a/pump/medtrum/src/main/res/values/strings.xml +++ b/pump/medtrum/src/main/res/values/strings.xml @@ -7,7 +7,6 @@ medtrum_session_token patch_id actual_basal_profile - last_basal_type current_sequence_number synced_sequence_number