Use timeout in connect states, other minor changes

This commit is contained in:
jbr7rr 2023-05-29 14:40:08 +02:00
parent 37a6a4f271
commit 3c8faa6723
4 changed files with 110 additions and 86 deletions

View file

@ -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 {

View file

@ -66,7 +66,15 @@ class MedtrumPump @Inject constructor(
set(value) {
_primeProgress.value = value
}
private var _lastBasalType: MutableStateFlow<BasalType> = MutableStateFlow(BasalType.NONE)
val lastBasalTypeFlow: StateFlow<BasalType> = _lastBasalType
var lastBasalType: BasalType
get() = _lastBasalType.value
set(value) {
_lastBasalType.value = value
}
private val _lastBasalRate = MutableStateFlow(0.0)
val lastBasalRateFlow: StateFlow<Double> = _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<BasalType> = MutableStateFlow(BasalType.NONE)
val lastBasalTypeFlow: StateFlow<BasalType> = _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<BasalType>()[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 {

View file

@ -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
}
}
}

View file

@ -7,7 +7,6 @@
<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>