combov2: Replace unsafe casts

This commit is contained in:
Carlos Rafael Giani 2023-03-12 13:19:33 +01:00
parent cc4cd2dc04
commit bec7a4aa97
2 changed files with 62 additions and 44 deletions

View file

@ -5,6 +5,7 @@ import info.nightscout.comboctl.base.CurrentTbrState
import info.nightscout.comboctl.base.InvariantPumpData import info.nightscout.comboctl.base.InvariantPumpData
import info.nightscout.comboctl.base.Nonce import info.nightscout.comboctl.base.Nonce
import info.nightscout.comboctl.base.PumpStateStore import info.nightscout.comboctl.base.PumpStateStore
import info.nightscout.comboctl.base.PumpStateStoreAccessException
import info.nightscout.comboctl.base.Tbr import info.nightscout.comboctl.base.Tbr
import info.nightscout.comboctl.base.toBluetoothAddress import info.nightscout.comboctl.base.toBluetoothAddress
import info.nightscout.comboctl.base.toCipher import info.nightscout.comboctl.base.toCipher
@ -151,7 +152,7 @@ class AAPSPumpStateStore(
timestamp = Instant.fromEpochSeconds(tbrTimestamp), timestamp = Instant.fromEpochSeconds(tbrTimestamp),
percentage = tbrPercentage, percentage = tbrPercentage,
durationInMinutes = tbrDuration, durationInMinutes = tbrDuration,
type = Tbr.Type.fromStringId(tbrType)!! type = Tbr.Type.fromStringId(tbrType) ?: throw PumpStateStoreAccessException(pumpAddress, "Invalid type \"$tbrType\"")
)) ))
else else
CurrentTbrState.NoTbrOngoing CurrentTbrState.NoTbrOngoing

View file

@ -290,7 +290,8 @@ class ComboV2Plugin @Inject constructor (
} }
aapsLogger.debug(LTag.PUMP, "Creating bluetooth interface") aapsLogger.debug(LTag.PUMP, "Creating bluetooth interface")
bluetoothInterface = AndroidBluetoothInterface(context) val newBluetoothInterface = AndroidBluetoothInterface(context)
bluetoothInterface = newBluetoothInterface
aapsLogger.info(LTag.PUMP, "Continuing combov2 driver start in coroutine") aapsLogger.info(LTag.PUMP, "Continuing combov2 driver start in coroutine")
@ -307,13 +308,13 @@ class ComboV2Plugin @Inject constructor (
aapsLogger.debug(LTag.PUMP, "Setting up bluetooth interface") aapsLogger.debug(LTag.PUMP, "Setting up bluetooth interface")
try { try {
bluetoothInterface!!.setup() newBluetoothInterface.setup()
rxBus.send(EventDismissNotification(Notification.BLUETOOTH_NOT_ENABLED)) rxBus.send(EventDismissNotification(Notification.BLUETOOTH_NOT_ENABLED))
aapsLogger.debug(LTag.PUMP, "Setting up pump manager") aapsLogger.debug(LTag.PUMP, "Setting up pump manager")
pumpManager = ComboCtlPumpManager(bluetoothInterface!!, pumpStateStore) val newPumpManager = ComboCtlPumpManager(newBluetoothInterface, pumpStateStore)
pumpManager!!.setup { newPumpManager.setup {
_pairedStateUIFlow.value = false _pairedStateUIFlow.value = false
unpairing = false unpairing = false
} }
@ -325,8 +326,10 @@ class ComboV2Plugin @Inject constructor (
// used as the backing store for the isPaired() function, // used as the backing store for the isPaired() function,
// so setting up that UI state flow equals updating that // so setting up that UI state flow equals updating that
// paired state. // paired state.
val paired = pumpManager!!.getPairedPumpAddresses().isNotEmpty() val paired = newPumpManager.getPairedPumpAddresses().isNotEmpty()
_pairedStateUIFlow.value = paired _pairedStateUIFlow.value = paired
pumpManager = newPumpManager
} catch (_: BluetoothNotEnabledException) { } catch (_: BluetoothNotEnabledException) {
uiInteraction.addNotification( uiInteraction.addNotification(
Notification.BLUETOOTH_NOT_ENABLED, Notification.BLUETOOTH_NOT_ENABLED,
@ -549,18 +552,16 @@ class ComboV2Plugin @Inject constructor (
} }
try { try {
runBlocking { val curPumpManager = pumpManager ?: throw Error("Could not get pump manager; this should not happen. Please report this as a bug.")
pump = pumpManager?.acquirePump(bluetoothAddress, activeBasalProfile) { event -> handlePumpEvent(event) }
val acquiredPump = runBlocking {
curPumpManager.acquirePump(bluetoothAddress, activeBasalProfile) { event -> handlePumpEvent(event) }
} }
if (pump == null) { pump = acquiredPump
aapsLogger.error(LTag.PUMP, "Could not get pump instance - pump state store may be corrupted")
unpairDueToPumpDataError()
return
}
_bluetoothAddressUIFlow.value = bluetoothAddress.toString() _bluetoothAddressUIFlow.value = bluetoothAddress.toString()
_serialNumberUIFlow.value = pumpManager!!.getPumpID(bluetoothAddress) _serialNumberUIFlow.value = curPumpManager.getPumpID(bluetoothAddress)
rxBus.send(EventDismissNotification(Notification.BLUETOOTH_NOT_ENABLED)) rxBus.send(EventDismissNotification(Notification.BLUETOOTH_NOT_ENABLED))
@ -570,7 +571,7 @@ class ComboV2Plugin @Inject constructor (
stateAndStatusFlowsDeferred = pumpCoroutineScope.async { stateAndStatusFlowsDeferred = pumpCoroutineScope.async {
coroutineScope { coroutineScope {
pump!!.stateFlow acquiredPump.stateFlow
.onEach { pumpState -> .onEach { pumpState ->
val driverState = when (pumpState) { val driverState = when (pumpState) {
// The Disconnected pump state is ignored, since the Disconnected // The Disconnected pump state is ignored, since the Disconnected
@ -591,7 +592,7 @@ class ComboV2Plugin @Inject constructor (
setDriverState(driverState) setDriverState(driverState)
} }
.launchIn(this) .launchIn(this)
pump!!.statusFlow acquiredPump.statusFlow
.onEach { newPumpStatus -> .onEach { newPumpStatus ->
if (newPumpStatus == null) if (newPumpStatus == null)
return@onEach return@onEach
@ -613,7 +614,7 @@ class ComboV2Plugin @Inject constructor (
rxBus.send(EventRefreshOverview("ComboV2 pump status updated")) rxBus.send(EventRefreshOverview("ComboV2 pump status updated"))
} }
.launchIn(this) .launchIn(this)
pump!!.lastBolusFlow acquiredPump.lastBolusFlow
.onEach { lastBolus -> .onEach { lastBolus ->
if (lastBolus == null) if (lastBolus == null)
return@onEach return@onEach
@ -621,7 +622,7 @@ class ComboV2Plugin @Inject constructor (
_lastBolusUIFlow.value = lastBolus _lastBolusUIFlow.value = lastBolus
} }
.launchIn(this) .launchIn(this)
pump!!.currentTbrFlow acquiredPump.currentTbrFlow
.onEach { currentTbr -> .onEach { currentTbr ->
_currentTbrUIFlow.value = currentTbr _currentTbrUIFlow.value = currentTbr
} }
@ -629,7 +630,7 @@ class ComboV2Plugin @Inject constructor (
} }
} }
setupUiFlows() setupUiFlows(acquiredPump)
//// ////
// The actual connect procedure begins here. // The actual connect procedure begins here.
@ -814,6 +815,8 @@ class ComboV2Plugin @Inject constructor (
} }
} }
val acquiredPump = getAcquiredPump()
rxBus.send(EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED)) rxBus.send(EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED))
rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE)) rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE))
@ -825,7 +828,7 @@ class ComboV2Plugin @Inject constructor (
runBlocking { runBlocking {
try { try {
executeCommand { executeCommand {
if (pump!!.setBasalProfile(requestedBasalProfile)) { if (acquiredPump.setBasalProfile(requestedBasalProfile)) {
aapsLogger.debug(LTag.PUMP, "Basal profiles are different; new profile set") aapsLogger.debug(LTag.PUMP, "Basal profiles are different; new profile set")
activeBasalProfile = requestedBasalProfile activeBasalProfile = requestedBasalProfile
updateBaseBasalRateUI() updateBaseBasalRateUI()
@ -973,6 +976,8 @@ class ComboV2Plugin @Inject constructor (
// (Also, a zero insulin value makes no sense when bolusing.) // (Also, a zero insulin value makes no sense when bolusing.)
require((detailedBolusInfo.insulin > 0) && (detailedBolusInfo.carbs <= 0.0)) { detailedBolusInfo.toString() } require((detailedBolusInfo.insulin > 0) && (detailedBolusInfo.carbs <= 0.0)) { detailedBolusInfo.toString() }
val acquiredPump = getAcquiredPump()
val requestedBolusAmount = detailedBolusInfo.insulin.iuToCctlBolus() val requestedBolusAmount = detailedBolusInfo.insulin.iuToCctlBolus()
val bolusReason = when (detailedBolusInfo.bolusType) { val bolusReason = when (detailedBolusInfo.bolusType) {
DetailedBolusInfo.BolusType.NORMAL -> ComboCtlPump.StandardBolusReason.NORMAL DetailedBolusInfo.BolusType.NORMAL -> ComboCtlPump.StandardBolusReason.NORMAL
@ -1006,7 +1011,7 @@ class ComboV2Plugin @Inject constructor (
) )
val bolusProgressJob = pumpCoroutineScope.launch { val bolusProgressJob = pumpCoroutineScope.launch {
pump!!.bolusDeliveryProgressFlow acquiredPump.bolusDeliveryProgressFlow
.collect { progressReport -> .collect { progressReport ->
when (progressReport.stage) { when (progressReport.stage) {
is RTCommandProgressStage.DeliveringBolus -> { is RTCommandProgressStage.DeliveringBolus -> {
@ -1029,14 +1034,16 @@ class ComboV2Plugin @Inject constructor (
// Run the delivery in a sub-coroutine to be able // Run the delivery in a sub-coroutine to be able
// to cancel it via stopBolusDelivering(). // to cancel it via stopBolusDelivering().
val newBolusJob = pumpCoroutineScope.async { val newBolusJob = pumpCoroutineScope.async {
// Store a local reference to the Pump instance. "pump" // NOTE: Above, we take a local reference to the acquired Pump instance,
// is set to null in case of an error, because then, // with a check that throws an exception in case the "pump" member is
// disconnectInternal() is called (which sets pump to null). // null. This local reference is particularly important inside this
// However, we still need to access the last delivered bolus // coroutine, because the "pump" member is set to null in case of an
// from the pump's lastBolusFlow, even if an error happened. // error or other disconnect reason (see disconnectInternal()). However,
// Solve this by storing this reference and accessing the // we still need to access the last delivered bolus inside this coroutine
// lastBolusFlow through it. // from the pump's lastBolusFlow, even if an error happened. Accessing
val acquiredPump = pump!! // it through the "pump" member would then result in an NPE. This is
// solved by instead accessing the lastBolusFlow through the local
// "acquiredPump" reference.
try { try {
executeCommand { executeCommand {
@ -1216,11 +1223,13 @@ class ComboV2Plugin @Inject constructor (
return return
} }
val acquiredPump = getAcquiredPump()
runBlocking { runBlocking {
try { try {
executeCommand { executeCommand {
val tbrComment = when (pump!!.setTbr(percentage, durationInMinutes, tbrType, force100Percent)) { val tbrComment = when (acquiredPump.setTbr(percentage, durationInMinutes, tbrType, force100Percent)) {
ComboCtlPump.SetTbrOutcome.SET_NORMAL_TBR -> ComboCtlPump.SetTbrOutcome.SET_NORMAL_TBR ->
rh.gs(R.string.combov2_setting_tbr_succeeded) rh.gs(R.string.combov2_setting_tbr_succeeded)
ComboCtlPump.SetTbrOutcome.SET_EMULATED_100_TBR -> ComboCtlPump.SetTbrOutcome.SET_EMULATED_100_TBR ->
@ -1373,8 +1382,9 @@ class ComboV2Plugin @Inject constructor (
override fun serialNumber(): String { override fun serialNumber(): String {
val bluetoothAddress = getBluetoothAddress() val bluetoothAddress = getBluetoothAddress()
return if ((bluetoothAddress != null) && (pumpManager != null)) val curPumpManager = pumpManager
pumpManager!!.getPumpID(bluetoothAddress) return if ((bluetoothAddress != null) && (curPumpManager != null))
curPumpManager.getPumpID(bluetoothAddress)
else else
rh.gs(R.string.combov2_not_paired) rh.gs(R.string.combov2_not_paired)
} }
@ -1442,6 +1452,7 @@ class ComboV2Plugin @Inject constructor (
override fun loadTDDs(): PumpEnactResult { override fun loadTDDs(): PumpEnactResult {
val pumpEnactResult = PumpEnactResult(injector) val pumpEnactResult = PumpEnactResult(injector)
val acquiredPump = getAcquiredPump()
runBlocking { runBlocking {
try { try {
@ -1449,7 +1460,7 @@ class ComboV2Plugin @Inject constructor (
val tddMap = mutableMapOf<Long, Int>() val tddMap = mutableMapOf<Long, Int>()
executeCommand { executeCommand {
val tddHistory = pump!!.fetchTDDHistory() val tddHistory = acquiredPump.fetchTDDHistory()
tddHistory tddHistory
.filter { it.totalDailyAmount >= 1 } .filter { it.totalDailyAmount >= 1 }
@ -1771,11 +1782,11 @@ class ComboV2Plugin @Inject constructor (
/*** Misc private functions ***/ /*** Misc private functions ***/
private fun setupUiFlows() { private fun setupUiFlows(acquiredPump: ComboCtlPump) {
pumpUIFlowsDeferred = pumpCoroutineScope.async { pumpUIFlowsDeferred = pumpCoroutineScope.async {
try { try {
coroutineScope { coroutineScope {
pump!!.connectProgressFlow acquiredPump.connectProgressFlow
.onEach { progressReport -> .onEach { progressReport ->
val description = when (val progStage = progressReport.stage) { val description = when (val progStage = progressReport.stage) {
is BasicProgressStage.EstablishingBtConnection -> is BasicProgressStage.EstablishingBtConnection ->
@ -1793,7 +1804,7 @@ class ComboV2Plugin @Inject constructor (
} }
.launchIn(this) .launchIn(this)
pump!!.setDateTimeProgressFlow acquiredPump.setDateTimeProgressFlow
.onEach { progressReport -> .onEach { progressReport ->
val description = when (progressReport.stage) { val description = when (progressReport.stage) {
RTCommandProgressStage.SettingDateTimeHour, RTCommandProgressStage.SettingDateTimeHour,
@ -1810,7 +1821,7 @@ class ComboV2Plugin @Inject constructor (
} }
.launchIn(this) .launchIn(this)
pump!!.getBasalProfileFlow acquiredPump.getBasalProfileFlow
.onEach { progressReport -> .onEach { progressReport ->
val description = when (val stage = progressReport.stage) { val description = when (val stage = progressReport.stage) {
is RTCommandProgressStage.GettingBasalProfile -> is RTCommandProgressStage.GettingBasalProfile ->
@ -1824,7 +1835,7 @@ class ComboV2Plugin @Inject constructor (
} }
.launchIn(this) .launchIn(this)
pump!!.setBasalProfileFlow acquiredPump.setBasalProfileFlow
.onEach { progressReport -> .onEach { progressReport ->
val description = when (val stage = progressReport.stage) { val description = when (val stage = progressReport.stage) {
is RTCommandProgressStage.SettingBasalProfile -> is RTCommandProgressStage.SettingBasalProfile ->
@ -1838,7 +1849,7 @@ class ComboV2Plugin @Inject constructor (
} }
.launchIn(this) .launchIn(this)
pump!!.bolusDeliveryProgressFlow acquiredPump.bolusDeliveryProgressFlow
.onEach { progressReport -> .onEach { progressReport ->
val description = when (val stage = progressReport.stage) { val description = when (val stage = progressReport.stage) {
is RTCommandProgressStage.DeliveringBolus -> is RTCommandProgressStage.DeliveringBolus ->
@ -1856,7 +1867,7 @@ class ComboV2Plugin @Inject constructor (
} }
.launchIn(this) .launchIn(this)
pump!!.parsedDisplayFrameFlow acquiredPump.parsedDisplayFrameFlow
.onEach { parsedDisplayFrame -> .onEach { parsedDisplayFrame ->
_displayFrameUIFlow.emit( _displayFrameUIFlow.emit(
parsedDisplayFrame?.displayFrame ?: NullDisplayFrame parsedDisplayFrame?.displayFrame ?: NullDisplayFrame
@ -2058,7 +2069,11 @@ class ComboV2Plugin @Inject constructor (
// It makes no sense to reach this location with pump // It makes no sense to reach this location with pump
// being null due to the checks above. // being null due to the checks above.
assert(pump != null) val pumpToDisconnect = pump
if (pumpToDisconnect == null) {
aapsLogger.error(LTag.PUMP, "Current pump is already null")
return
}
// Run these operations in a coroutine to be able to wait // Run these operations in a coroutine to be able to wait
// until the disconnect really completes and the UI flows // until the disconnect really completes and the UI flows
@ -2096,17 +2111,17 @@ class ComboV2Plugin @Inject constructor (
// the Pump.disconnect() call shuts down the RFCOMM socket, // the Pump.disconnect() call shuts down the RFCOMM socket,
// making all send/receive calls fail. // making all send/receive calls fail.
if (pump!!.stateFlow.value == ComboCtlPump.State.Connecting) { if (pumpToDisconnect.stateFlow.value == ComboCtlPump.State.Connecting) {
// Case #1 from above // Case #1 from above
aapsLogger.debug(LTag.PUMP, "Cancelling ongoing connect attempt") aapsLogger.debug(LTag.PUMP, "Cancelling ongoing connect attempt")
connectionSetupJob?.cancel() connectionSetupJob?.cancel()
pump?.disconnect() pumpToDisconnect.disconnect()
connectionSetupJob?.join() connectionSetupJob?.join()
} else { } else {
// Case #2 from above // Case #2 from above
aapsLogger.debug(LTag.PUMP, "Disconnecting Combo (if not disconnected already by a cancelling request)") aapsLogger.debug(LTag.PUMP, "Disconnecting Combo (if not disconnected already by a cancelling request)")
connectionSetupJob?.cancelAndJoin() connectionSetupJob?.cancelAndJoin()
pump?.disconnect() pumpToDisconnect.disconnect()
} }
aapsLogger.debug(LTag.PUMP, "Combo disconnected; cancelling UI flows coroutine") aapsLogger.debug(LTag.PUMP, "Combo disconnected; cancelling UI flows coroutine")
@ -2339,6 +2354,8 @@ class ComboV2Plugin @Inject constructor (
private fun getBluetoothAddress(): ComboCtlBluetoothAddress? = private fun getBluetoothAddress(): ComboCtlBluetoothAddress? =
pumpManager?.getPairedPumpAddresses()?.firstOrNull() pumpManager?.getPairedPumpAddresses()?.firstOrNull()
private fun getAcquiredPump() = pump ?: throw Error("There is no currently acquired pump; this should not happen. Please report this as a bug.")
private fun isDisconnected() = private fun isDisconnected() =
when (driverStateFlow.value) { when (driverStateFlow.value) {
DriverState.NotInitialized, DriverState.NotInitialized,