merge
This commit is contained in:
commit
e8bc50f458
|
@ -23,7 +23,10 @@ abstract class OmnipodWizardModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@OmnipodPluginQualifier
|
@OmnipodPluginQualifier
|
||||||
fun providesViewModelFactory(@OmnipodPluginQualifier viewModels: MutableMap<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>): ViewModelProvider.Factory {
|
fun providesViewModelFactory(
|
||||||
|
@OmnipodPluginQualifier
|
||||||
|
viewModels: MutableMap<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
|
||||||
|
): ViewModelProvider.Factory {
|
||||||
return ViewModelFactory(viewModels)
|
return ViewModelFactory(viewModels)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import info.nightscout.androidaps.queue.commands.CustomCommand;
|
import info.nightscout.androidaps.queue.commands.CustomCommand;
|
||||||
|
|
||||||
public final class CommandAcknowledgeAlerts implements CustomCommand {
|
public final class CommandSilenceAlerts implements CustomCommand {
|
||||||
@NotNull @Override public String getStatusDescription() {
|
@NotNull @Override public String getStatusDescription() {
|
||||||
return "ACKNOWLEDGE ALERTS";
|
return "ACKNOWLEDGE ALERTS";
|
||||||
}
|
}
|
|
@ -41,7 +41,11 @@ class AttachPodFragment : InfoFragmentBase() {
|
||||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||||
.setTitle(getString(getTitleId()))
|
.setTitle(getString(getTitleId()))
|
||||||
.setMessage(getString(R.string.omnipod_common_pod_activation_wizard_attach_pod_confirm_insert_cannula_text))
|
.setMessage(getString(R.string.omnipod_common_pod_activation_wizard_attach_pod_confirm_insert_cannula_text))
|
||||||
.setPositiveButton(getString(R.string.omnipod_common_ok)) { _, _ -> findNavController().navigate(getNextPageActionId()) }
|
.setPositiveButton(getString(R.string.omnipod_common_ok)) { _, _ ->
|
||||||
|
findNavController().navigate(
|
||||||
|
getNextPageActionId()
|
||||||
|
)
|
||||||
|
}
|
||||||
.setNegativeButton(getString(R.string.omnipod_common_cancel), null)
|
.setNegativeButton(getString(R.string.omnipod_common_cancel), null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,8 @@ abstract class ActionFragmentBase : WizardFragmentBase() {
|
||||||
binding.navButtonsLayout.buttonNext.isEnabled = false
|
binding.navButtonsLayout.buttonNext.isEnabled = false
|
||||||
view.findViewById<TextView>(R.id.omnipod_wizard_action_page_text).setText(getTextId())
|
view.findViewById<TextView>(R.id.omnipod_wizard_action_page_text).setText(getTextId())
|
||||||
|
|
||||||
view.findViewById<Button>(R.id.omnipod_wizard_button_retry).setOnClickListener { actionViewModel.executeAction() }
|
view.findViewById<Button>(R.id.omnipod_wizard_button_retry)
|
||||||
|
.setOnClickListener { actionViewModel.executeAction() }
|
||||||
|
|
||||||
actionViewModel.isActionExecutingLiveData.observe(viewLifecycleOwner, { isExecuting ->
|
actionViewModel.isActionExecutingLiveData.observe(viewLifecycleOwner, { isExecuting ->
|
||||||
if (isExecuting) {
|
if (isExecuting) {
|
||||||
|
@ -33,7 +34,8 @@ abstract class ActionFragmentBase : WizardFragmentBase() {
|
||||||
view.findViewById<Button>(R.id.omnipod_wizard_button_discard_pod).visibility = View.GONE
|
view.findViewById<Button>(R.id.omnipod_wizard_button_discard_pod).visibility = View.GONE
|
||||||
view.findViewById<Button>(R.id.omnipod_wizard_button_retry).visibility = View.GONE
|
view.findViewById<Button>(R.id.omnipod_wizard_button_retry).visibility = View.GONE
|
||||||
}
|
}
|
||||||
view.findViewById<ProgressBar>(R.id.omnipod_wizard_action_progress_indication).visibility = isExecuting.toVisibility()
|
view.findViewById<ProgressBar>(R.id.omnipod_wizard_action_progress_indication).visibility =
|
||||||
|
isExecuting.toVisibility()
|
||||||
view.findViewById<Button>(R.id.button_cancel).isEnabled = !isExecuting
|
view.findViewById<Button>(R.id.button_cancel).isEnabled = !isExecuting
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -42,9 +44,12 @@ abstract class ActionFragmentBase : WizardFragmentBase() {
|
||||||
val isExecuting = isActionExecuting()
|
val isExecuting = isActionExecuting()
|
||||||
|
|
||||||
view.findViewById<Button>(R.id.button_next).isEnabled = result.success
|
view.findViewById<Button>(R.id.button_next).isEnabled = result.success
|
||||||
view.findViewById<ImageView>(R.id.omnipod_wizard_action_success).visibility = result.success.toVisibility()
|
view.findViewById<ImageView>(R.id.omnipod_wizard_action_success).visibility =
|
||||||
view.findViewById<TextView>(R.id.omnipod_wizard_action_error).visibility = (!isExecuting && !result.success).toVisibility()
|
result.success.toVisibility()
|
||||||
view.findViewById<Button>(R.id.omnipod_wizard_button_retry).visibility = (!isExecuting && !result.success).toVisibility()
|
view.findViewById<TextView>(R.id.omnipod_wizard_action_error).visibility =
|
||||||
|
(!isExecuting && !result.success).toVisibility()
|
||||||
|
view.findViewById<Button>(R.id.omnipod_wizard_button_retry).visibility =
|
||||||
|
(!isExecuting && !result.success).toVisibility()
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
view.findViewById<TextView>(R.id.omnipod_wizard_action_error).text = result.comment
|
view.findViewById<TextView>(R.id.omnipod_wizard_action_error).text = result.comment
|
||||||
|
|
|
@ -47,7 +47,8 @@ abstract class WizardFragmentBase : DaggerFragment() {
|
||||||
|
|
||||||
if (nextPage == null) {
|
if (nextPage == null) {
|
||||||
binding.navButtonsLayout.buttonNext.text = getString(R.string.omnipod_common_wizard_button_finish)
|
binding.navButtonsLayout.buttonNext.text = getString(R.string.omnipod_common_wizard_button_finish)
|
||||||
binding.navButtonsLayout.buttonNext.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.omnipod_wizard_finish_button, context?.theme))
|
binding.navButtonsLayout.buttonNext.backgroundTintList =
|
||||||
|
ColorStateList.valueOf(resources.getColor(R.color.omnipod_wizard_finish_button, context?.theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProgressIndication()
|
updateProgressIndication()
|
||||||
|
|
|
@ -11,13 +11,23 @@ import info.nightscout.androidaps.plugins.common.ManufacturerType
|
||||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
||||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
|
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
|
||||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.*
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram
|
||||||
import info.nightscout.androidaps.queue.commands.CustomCommand
|
import info.nightscout.androidaps.queue.commands.CustomCommand
|
||||||
import info.nightscout.androidaps.utils.TimeChangeType
|
import info.nightscout.androidaps.utils.TimeChangeType
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import io.reactivex.Single
|
||||||
|
import io.reactivex.rxkotlin.blockingSubscribeBy
|
||||||
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -25,6 +35,8 @@ import javax.inject.Singleton
|
||||||
class OmnipodDashPumpPlugin @Inject constructor(
|
class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
private val omnipodManager: OmnipodDashManager,
|
private val omnipodManager: OmnipodDashManager,
|
||||||
private val podStateManager: OmnipodDashPodStateManager,
|
private val podStateManager: OmnipodDashPodStateManager,
|
||||||
|
private val sp: SP,
|
||||||
|
private val profileFunction: ProfileFunction,
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
|
@ -33,13 +45,13 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val pluginDescription = PluginDescription() //
|
private val pluginDescription = PluginDescription()
|
||||||
.mainType(PluginType.PUMP) //
|
.mainType(PluginType.PUMP)
|
||||||
.fragmentClass(OmnipodDashOverviewFragment::class.java.name) //
|
.fragmentClass(OmnipodDashOverviewFragment::class.java.name)
|
||||||
.pluginIcon(R.drawable.ic_pod_128)
|
.pluginIcon(R.drawable.ic_pod_128)
|
||||||
.pluginName(R.string.omnipod_dash_name) //
|
.pluginName(R.string.omnipod_dash_name)
|
||||||
.shortName(R.string.omnipod_dash_name_short) //
|
.shortName(R.string.omnipod_dash_name_short)
|
||||||
.preferencesId(R.xml.omnipod_dash_preferences) //
|
.preferencesId(R.xml.omnipod_dash_preferences)
|
||||||
.description(R.string.omnipod_dash_pump_description)
|
.description(R.string.omnipod_dash_pump_description)
|
||||||
|
|
||||||
private val pumpDescription = PumpDescription(PumpType.Omnipod_Dash)
|
private val pumpDescription = PumpDescription(PumpType.Omnipod_Dash)
|
||||||
|
@ -51,19 +63,17 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isSuspended(): Boolean {
|
override fun isSuspended(): Boolean {
|
||||||
// TODO
|
return podStateManager.isSuspended
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isBusy(): Boolean {
|
override fun isBusy(): Boolean {
|
||||||
// prevents the queue from executing commands
|
// prevents the queue from executing commands
|
||||||
// TODO
|
return podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isConnected(): Boolean {
|
override fun isConnected(): Boolean {
|
||||||
// TODO
|
// TODO
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isConnecting(): Boolean {
|
override fun isConnecting(): Boolean {
|
||||||
|
@ -93,40 +103,136 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPumpStatus(reason: String) {
|
override fun getPumpStatus(reason: String) {
|
||||||
// TODO
|
// TODO history
|
||||||
|
|
||||||
|
omnipodManager.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE).blockingSubscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in getPumpStatus: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", throwable)
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("getPumpStatus completed")
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||||
// TODO
|
// TODO history
|
||||||
return PumpEnactResult(injector).success(true).enacted(true)
|
|
||||||
|
return Single.create<PumpEnactResult> { source ->
|
||||||
|
omnipodManager.setBasalProgram(mapProfileToBasalProgram(profile)).subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in setNewBasalProfile: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in setNewBasalProfile", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("setNewBasalProfile completed")
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(true).enacted(true))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||||
// TODO
|
if (podStateManager.basalProgram == null) {
|
||||||
return true
|
// We don't have an active Pod. Return true here because the next Pod will use the currently active profile
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return podStateManager.basalProgram!! == mapProfileToBasalProgram(profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lastDataTime(): Long {
|
override fun lastDataTime(): Long {
|
||||||
// TODO
|
return podStateManager.lastConnection
|
||||||
return System.currentTimeMillis()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val baseBasalRate: Double
|
override val baseBasalRate: Double
|
||||||
get() = 0.0 // TODO
|
get() {
|
||||||
|
if (podStateManager.basalProgram == null) {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
return podStateManager.basalProgram!!.rateAt(Date())
|
||||||
|
}
|
||||||
|
|
||||||
override val reservoirLevel: Double
|
override val reservoirLevel: Double
|
||||||
get() = 0.0 // TODO
|
get() {
|
||||||
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)) {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Omnipod only reports reservoir level when there's < 1023 pulses left
|
||||||
|
return podStateManager.pulsesRemaining?.let {
|
||||||
|
it * 0.05
|
||||||
|
} ?: 75.0
|
||||||
|
}
|
||||||
|
|
||||||
override val batteryLevel: Int
|
override val batteryLevel: Int
|
||||||
|
// Omnipod Dash doesn't report it's battery level. We return 0 here and hide related fields in the UI
|
||||||
get() = 0
|
get() = 0
|
||||||
|
|
||||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||||
// TODO
|
// TODO history
|
||||||
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
|
// TODO update Treatments (?)
|
||||||
|
// TODO bolus progress
|
||||||
|
// TODO report actual delivered amount after Pod Alarm and bolus cancellation
|
||||||
|
|
||||||
|
return Single.create<PumpEnactResult> { source ->
|
||||||
|
val bolusBeeps = sp.getBoolean(R.string.key_omnipod_common_bolus_beeps_enabled, false)
|
||||||
|
|
||||||
|
omnipodManager.bolus(
|
||||||
|
detailedBolusInfo.insulin,
|
||||||
|
bolusBeeps,
|
||||||
|
bolusBeeps
|
||||||
|
).subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in deliverTreatment: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in deliverTreatment", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("deliverTreatment completed")
|
||||||
|
source.onSuccess(
|
||||||
|
PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(detailedBolusInfo.insulin)
|
||||||
|
.carbsDelivered(detailedBolusInfo.carbs)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stopBolusDelivering() {
|
override fun stopBolusDelivering() {
|
||||||
// TODO
|
// TODO history
|
||||||
|
// TODO update Treatments (?)
|
||||||
|
|
||||||
|
omnipodManager.stopBolus().blockingSubscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in stopBolusDelivering: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in stopBolusDelivering", throwable)
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("stopBolusDelivering completed")
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTempBasalAbsolute(
|
override fun setTempBasalAbsolute(
|
||||||
|
@ -135,8 +241,33 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
profile: Profile,
|
profile: Profile,
|
||||||
enforceNew: Boolean
|
enforceNew: Boolean
|
||||||
): PumpEnactResult {
|
): PumpEnactResult {
|
||||||
// TODO
|
// TODO history
|
||||||
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
|
// TODO update Treatments
|
||||||
|
|
||||||
|
return Single.create<PumpEnactResult> { source ->
|
||||||
|
omnipodManager.setTempBasal(
|
||||||
|
absoluteRate,
|
||||||
|
durationInMinutes.toShort()
|
||||||
|
).subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in setTempBasalAbsolute: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in setTempBasalAbsolute", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("setTempBasalAbsolute completed")
|
||||||
|
source.onSuccess(
|
||||||
|
PumpEnactResult(injector).success(true).enacted(true).absolute(absoluteRate)
|
||||||
|
.duration(durationInMinutes)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTempBasalPercent(
|
override fun setTempBasalPercent(
|
||||||
|
@ -157,8 +288,29 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||||
// TODO
|
// TODO history
|
||||||
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
|
// TODO update Treatments
|
||||||
|
|
||||||
|
return Single.create<PumpEnactResult> { source ->
|
||||||
|
omnipodManager.stopTempBasal().subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in cancelTempBasal: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in cancelTempBasal", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("cancelTempBasal completed")
|
||||||
|
source.onSuccess(
|
||||||
|
PumpEnactResult(injector).success(true).enacted(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelExtendedBolus(): PumpEnactResult {
|
override fun cancelExtendedBolus(): PumpEnactResult {
|
||||||
|
@ -183,8 +335,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialNumber(): String {
|
override fun serialNumber(): String {
|
||||||
// TODO
|
return if (podStateManager.uniqueId == null) {
|
||||||
return "TODO"
|
"n/a" // TODO i18n
|
||||||
|
} else {
|
||||||
|
podStateManager.uniqueId.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shortStatus(veryShort: Boolean): String {
|
override fun shortStatus(veryShort: Boolean): String {
|
||||||
|
@ -214,11 +369,190 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? {
|
override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? {
|
||||||
|
if (customCommand is CommandSilenceAlerts) {
|
||||||
|
return silenceAlerts()
|
||||||
|
}
|
||||||
|
if (customCommand is CommandSuspendDelivery) {
|
||||||
|
return suspendDelivery()
|
||||||
|
}
|
||||||
|
if (customCommand is CommandResumeDelivery) {
|
||||||
|
return resumeDelivery()
|
||||||
|
}
|
||||||
|
if (customCommand is CommandDeactivatePod) {
|
||||||
|
return deactivatePod()
|
||||||
|
}
|
||||||
|
if (customCommand is CommandHandleTimeChange) {
|
||||||
|
return handleTimeChange()
|
||||||
|
}
|
||||||
|
if (customCommand is CommandUpdateAlertConfiguration) {
|
||||||
|
return updateAlertConfiguration()
|
||||||
|
}
|
||||||
|
if (customCommand is CommandPlayTestBeep) {
|
||||||
|
return playTestBeep()
|
||||||
|
}
|
||||||
|
|
||||||
|
aapsLogger.warn(LTag.PUMP, "Unsupported custom command: " + customCommand.javaClass.name)
|
||||||
|
|
||||||
|
return PumpEnactResult(injector).success(false).enacted(false).comment(
|
||||||
|
resourceHelper.gs(
|
||||||
|
R.string.omnipod_common_error_unsupported_custom_command,
|
||||||
|
customCommand.javaClass.name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun silenceAlerts(): PumpEnactResult {
|
||||||
|
// TODO history
|
||||||
|
// TODO filter alert types
|
||||||
|
|
||||||
|
return podStateManager.activeAlerts?.let {
|
||||||
|
Single.create<PumpEnactResult> { source ->
|
||||||
|
omnipodManager.silenceAlerts(it).subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in silenceAlerts: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in silenceAlerts", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("silenceAlerts completed")
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(true))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
|
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No active alerts") // TODO i18n
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun suspendDelivery(): PumpEnactResult {
|
||||||
|
// TODO history
|
||||||
|
|
||||||
|
return Single.create<PumpEnactResult> { source ->
|
||||||
|
omnipodManager.suspendDelivery().subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in suspendDelivery: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in suspendDelivery", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("suspendDelivery completed")
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(true))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resumeDelivery(): PumpEnactResult {
|
||||||
|
// TODO history
|
||||||
|
|
||||||
|
return profileFunction.getProfile()?.let {
|
||||||
|
|
||||||
|
Single.create<PumpEnactResult> { source ->
|
||||||
|
omnipodManager.setBasalProgram(mapProfileToBasalProgram(it)).subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in resumeDelivery: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in resumeDelivery", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("resumeDelivery completed")
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(true))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
|
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deactivatePod(): PumpEnactResult {
|
||||||
|
// TODO history
|
||||||
|
|
||||||
|
return Single.create<PumpEnactResult> { source ->
|
||||||
|
omnipodManager.deactivatePod().subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in deactivatePod: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in deactivatePod", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("deactivatePod completed")
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(true))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleTimeChange(): PumpEnactResult {
|
||||||
// TODO
|
// TODO
|
||||||
return null
|
return PumpEnactResult(injector).success(false).enacted(false).comment("NOT IMPLEMENTED")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateAlertConfiguration(): PumpEnactResult {
|
||||||
|
// TODO
|
||||||
|
return PumpEnactResult(injector).success(false).enacted(false).comment("NOT IMPLEMENTED")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun playTestBeep(): PumpEnactResult {
|
||||||
|
// TODO history
|
||||||
|
|
||||||
|
return Single.create<PumpEnactResult> { source ->
|
||||||
|
omnipodManager.playBeep(BeepType.LONG_SINGLE_BEEP).subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent in playTestBeep: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error in playTestBeep", throwable)
|
||||||
|
source.onSuccess(PumpEnactResult(injector).success(false).enacted(false).comment(throwable.message))
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("playTestBeep completed")
|
||||||
|
source.onSuccess(
|
||||||
|
PumpEnactResult(injector).success(true).enacted(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
|
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
|
||||||
// TODO
|
val eventHandlingEnabled = sp.getBoolean(R.string.key_omnipod_common_time_change_event_enabled, false)
|
||||||
|
|
||||||
|
aapsLogger.info(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Time, Date and/or TimeZone changed. [timeChangeType=" + timeChangeType.name + ", eventHandlingEnabled=" + eventHandlingEnabled + "]"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if (timeChangeType == TimeChangeType.TimeChanged) {
|
||||||
|
aapsLogger.info(LTag.PUMP, "Ignoring time change because it is not a DST or TZ change")
|
||||||
|
return
|
||||||
|
} else if (!podStateManager.isPodRunning) {
|
||||||
|
aapsLogger.info(LTag.PUMP, "Ignoring time change because no Pod is active")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
aapsLogger.info(LTag.PUMP, "Handling time change")
|
||||||
|
|
||||||
|
commandQueue.customCommand(CommandHandleTimeChange(false), null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertTrigger
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertTrigger
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertType
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertType
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -14,9 +16,9 @@ interface OmnipodDashManager {
|
||||||
|
|
||||||
fun activatePodPart2(basalProgram: BasalProgram): Observable<PodEvent>
|
fun activatePodPart2(basalProgram: BasalProgram): Observable<PodEvent>
|
||||||
|
|
||||||
fun getStatus(): Observable<PodEvent>
|
fun getStatus(type: ResponseType.StatusResponseType): Observable<PodEvent>
|
||||||
|
|
||||||
fun setBasalProgram(program: BasalProgram): Observable<PodEvent>
|
fun setBasalProgram(basalProgram: BasalProgram): Observable<PodEvent>
|
||||||
|
|
||||||
fun suspendDelivery(): Observable<PodEvent>
|
fun suspendDelivery(): Observable<PodEvent>
|
||||||
|
|
||||||
|
@ -24,17 +26,17 @@ interface OmnipodDashManager {
|
||||||
|
|
||||||
fun setTempBasal(rate: Double, durationInMinutes: Short): Observable<PodEvent>
|
fun setTempBasal(rate: Double, durationInMinutes: Short): Observable<PodEvent>
|
||||||
|
|
||||||
fun cancelTempBasal(): Observable<PodEvent>
|
fun stopTempBasal(): Observable<PodEvent>
|
||||||
|
|
||||||
fun bolus(amount: Double): Observable<PodEvent>
|
fun bolus(units: Double, confirmationBeeps: Boolean, completionBeeps: Boolean): Observable<PodEvent>
|
||||||
|
|
||||||
fun cancelBolus(): Observable<PodEvent>
|
fun stopBolus(): Observable<PodEvent>
|
||||||
|
|
||||||
fun programBeeps(): Observable<PodEvent>
|
fun playBeep(beepType: BeepType): Observable<PodEvent>
|
||||||
|
|
||||||
fun programAlerts(alertConfigurations: List<AlertConfiguration>): Observable<PodEvent>
|
fun programAlerts(alertConfigurations: List<AlertConfiguration>): Observable<PodEvent>
|
||||||
|
|
||||||
fun silenceAlerts(alerts: EnumSet<AlertType>): Observable<PodEvent>
|
fun silenceAlerts(alertTypes: EnumSet<AlertType>): Observable<PodEvent>
|
||||||
|
|
||||||
fun deactivatePod(): Observable<PodEvent>
|
fun deactivatePod(): Observable<PodEvent>
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,17 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
private val aapsSchedulers: AapsSchedulers
|
private val aapsSchedulers: AapsSchedulers
|
||||||
) : OmnipodDashManager {
|
) : OmnipodDashManager {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val NONCE = 1229869870 // The Omnipod Dash seems to use a fixed nonce
|
||||||
|
}
|
||||||
|
|
||||||
private val observePodReadyForActivationPart1: Observable<PodEvent>
|
private val observePodReadyForActivationPart1: Observable<PodEvent>
|
||||||
get() = Observable.defer {
|
get() = Observable.defer {
|
||||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.PHASE_1_COMPLETED)) {
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.PHASE_1_COMPLETED)) {
|
||||||
Observable.empty()
|
Observable.empty()
|
||||||
} else {
|
} else {
|
||||||
|
// TODO introduce specialized Exception
|
||||||
Observable.error(IllegalStateException("Pod is in an incorrect state"))
|
Observable.error(IllegalStateException("Pod is in an incorrect state"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +48,27 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
) {
|
) {
|
||||||
Observable.empty()
|
Observable.empty()
|
||||||
} else {
|
} else {
|
||||||
|
// TODO introduce specialized Exception
|
||||||
|
Observable.error(IllegalStateException("Pod is in an incorrect state"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val observeUniqueIdSet: Observable<PodEvent>
|
||||||
|
get() = Observable.defer {
|
||||||
|
if (podStateManager.activationProgress.isAtLeast(ActivationProgress.SET_UNIQUE_ID)) {
|
||||||
|
Observable.empty()
|
||||||
|
} else {
|
||||||
|
// TODO introduce specialized Exception
|
||||||
|
Observable.error(IllegalStateException("Pod is in an incorrect state"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val observePodRunning: Observable<PodEvent>
|
||||||
|
get() = Observable.defer {
|
||||||
|
if (podStateManager.activationProgress == ActivationProgress.COMPLETED && podStateManager.podStatus!!.isRunning()) {
|
||||||
|
Observable.empty()
|
||||||
|
} else {
|
||||||
|
// TODO introduce specialized Exception
|
||||||
Observable.error(IllegalStateException("Pod is in an incorrect state"))
|
Observable.error(IllegalStateException("Pod is in an incorrect state"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,41 +94,48 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
ProgramBolusCommand.Builder()
|
ProgramBolusCommand.Builder()
|
||||||
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
.setNonce(1229869870) // TODO
|
.setNonce(NONCE)
|
||||||
.setNumberOfUnits(units)
|
.setNumberOfUnits(units)
|
||||||
.setDelayBetweenPulsesInEighthSeconds(rateInEighthPulsesPerSeconds)
|
.setDelayBetweenPulsesInEighthSeconds(rateInEighthPulsesPerSeconds)
|
||||||
.setProgramReminder(ProgramReminder(confirmationBeeps, completionBeeps, 0))
|
.setProgramReminder(ProgramReminder(confirmationBeeps, completionBeeps, 0))
|
||||||
.build()
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeSendGetPodStatusCommand(type: ResponseType.StatusResponseType = ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE): Observable<PodEvent> {
|
private fun observeSendGetPodStatusCommand(type: ResponseType.StatusResponseType = ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE): Observable<PodEvent> {
|
||||||
|
// TODO move somewhere else
|
||||||
|
val expectedResponseType = when (type) {
|
||||||
|
ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE -> DefaultStatusResponse::class
|
||||||
|
ResponseType.StatusResponseType.ALARM_STATUS -> AlarmStatusResponse::class
|
||||||
|
|
||||||
|
else -> return Observable.error(UnsupportedOperationException("No response type to class mapping for ${type.name}"))
|
||||||
|
}
|
||||||
|
|
||||||
return Observable.defer {
|
return Observable.defer {
|
||||||
bleManager.sendCommand(
|
bleManager.sendCommand(
|
||||||
GetStatusCommand.Builder()
|
GetStatusCommand.Builder()
|
||||||
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
.setStatusResponseType(type)
|
.setStatusResponseType(type)
|
||||||
.build()
|
.build(),
|
||||||
|
expectedResponseType
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val observeVerifyCannulaInsertion: Observable<PodEvent>
|
private val observeVerifyCannulaInsertion: Observable<PodEvent>
|
||||||
get() = Observable.defer {
|
get() = Observable.concat(
|
||||||
observeSendGetPodStatusCommand()
|
observeSendGetPodStatusCommand(),
|
||||||
.ignoreElements() //
|
Observable.defer {
|
||||||
.andThen(
|
if (podStateManager.podStatus == PodStatus.RUNNING_ABOVE_MIN_VOLUME) {
|
||||||
Observable.defer {
|
Observable.empty()
|
||||||
if (podStateManager.podStatus == PodStatus.RUNNING_ABOVE_MIN_VOLUME) {
|
} else {
|
||||||
Observable.empty()
|
Observable.error(IllegalStateException("Unexpected Pod status"))
|
||||||
} else {
|
}
|
||||||
Observable.error(IllegalStateException("Unexpected Pod status"))
|
}
|
||||||
}
|
)
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun observeSendProgramAlertsCommand(
|
private fun observeSendProgramAlertsCommand(
|
||||||
alertConfigurations: List<AlertConfiguration>,
|
alertConfigurations: List<AlertConfiguration>,
|
||||||
|
@ -112,74 +146,81 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
ProgramAlertsCommand.Builder()
|
ProgramAlertsCommand.Builder()
|
||||||
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
.setNonce(1229869870) // TODO
|
.setNonce(NONCE)
|
||||||
.setAlertConfigurations(alertConfigurations)
|
.setAlertConfigurations(alertConfigurations)
|
||||||
.build()
|
.setMultiCommandFlag(multiCommandFlag)
|
||||||
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeProgramBasalCommand(basalProgram: BasalProgram): Observable<PodEvent> {
|
private fun observeSendProgramBasalCommand(basalProgram: BasalProgram): Observable<PodEvent> {
|
||||||
return Observable.defer {
|
return Observable.defer {
|
||||||
|
val currentTime = Date()
|
||||||
|
logger.debug(LTag.PUMPCOMM, "Programming basal. currentTime={}, basalProgram={}", currentTime, basalProgram)
|
||||||
bleManager.sendCommand(
|
bleManager.sendCommand(
|
||||||
ProgramBasalCommand.Builder()
|
ProgramBasalCommand.Builder()
|
||||||
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
.setNonce(1229869870) // TODO
|
.setNonce(NONCE)
|
||||||
.setProgramReminder(ProgramReminder(atStart = false, atEnd = false, atInterval = 0))
|
.setProgramReminder(ProgramReminder(atStart = false, atEnd = false, atInterval = 0))
|
||||||
.setBasalProgram(basalProgram)
|
.setBasalProgram(basalProgram)
|
||||||
.setCurrentTime(Date())
|
.setCurrentTime(currentTime)
|
||||||
.build()
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
)
|
)
|
||||||
|
}.doOnComplete {
|
||||||
|
podStateManager.basalProgram = basalProgram
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val observeVerifyPrime: Observable<PodEvent>
|
private val observeVerifyPrime: Observable<PodEvent>
|
||||||
get() = Observable.defer {
|
get() = Observable.concat(
|
||||||
observeSendGetPodStatusCommand()
|
observeSendGetPodStatusCommand(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE),
|
||||||
.ignoreElements() //
|
Observable.defer {
|
||||||
.andThen(
|
if (podStateManager.podStatus == PodStatus.CLUTCH_DRIVE_ENGAGED) {
|
||||||
Observable.defer {
|
Observable.empty()
|
||||||
if (podStateManager.podStatus == PodStatus.CLUTCH_DRIVE_ENGAGED) {
|
} else {
|
||||||
Observable.empty()
|
Observable.error(IllegalStateException("Unexpected Pod status: got ${podStateManager.podStatus}, expected CLUTCH_DRIVE_ENGAGED"))
|
||||||
} else {
|
}
|
||||||
Observable.error(IllegalStateException("Unexpected Pod status"))
|
}
|
||||||
}
|
)
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val observeSendSetUniqueIdCommand: Observable<PodEvent>
|
private val observeSendSetUniqueIdCommand: Observable<PodEvent>
|
||||||
get() = Observable.defer {
|
get() = Observable.defer {
|
||||||
bleManager.sendCommand(
|
bleManager.sendCommand(
|
||||||
SetUniqueIdCommand.Builder() //
|
SetUniqueIdCommand.Builder()
|
||||||
.setSequenceNumber(podStateManager.messageSequenceNumber) //
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
.setUniqueId(podStateManager.uniqueId!!.toInt()) //
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
.setLotNumber(podStateManager.lotNumber!!.toInt()) //
|
.setLotNumber(podStateManager.lotNumber!!.toInt())
|
||||||
.setPodSequenceNumber(podStateManager.podSequenceNumber!!.toInt())
|
.setPodSequenceNumber(podStateManager.podSequenceNumber!!.toInt())
|
||||||
.setInitializationTime(Date())
|
.setInitializationTime(Date())
|
||||||
.build()
|
.build(),
|
||||||
) //
|
SetUniqueIdResponse::class
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val observeSendGetVersionCommand: Observable<PodEvent>
|
private val observeSendGetVersionCommand: Observable<PodEvent>
|
||||||
get() = Observable.defer {
|
get() = Observable.defer {
|
||||||
bleManager.sendCommand(
|
bleManager.sendCommand(
|
||||||
GetVersionCommand.Builder() //
|
GetVersionCommand.Builder()
|
||||||
.setSequenceNumber(podStateManager.messageSequenceNumber) //
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
.setUniqueId(DEFAULT_UNIQUE_ID) //
|
.setUniqueId(DEFAULT_UNIQUE_ID)
|
||||||
.build()
|
.build(),
|
||||||
) //
|
VersionResponse::class
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun activatePodPart1(lowReservoirAlertTrigger: AlertTrigger.ReservoirVolumeTrigger?): Observable<PodEvent> {
|
override fun activatePodPart1(lowReservoirAlertTrigger: AlertTrigger.ReservoirVolumeTrigger?): Observable<PodEvent> {
|
||||||
return Observable.concat(
|
return Observable.concat(
|
||||||
observePodReadyForActivationPart1,
|
observePodReadyForActivationPart1,
|
||||||
observePairNewPod,
|
observePairNewPod,
|
||||||
|
observeConnectToPod, // FIXME needed after disconnect; observePairNewPod does not connect in that case.
|
||||||
observeActivationPart1Commands(lowReservoirAlertTrigger)
|
observeActivationPart1Commands(lowReservoirAlertTrigger)
|
||||||
).doOnComplete(ActivationProgressUpdater(ActivationProgress.PHASE_1_COMPLETED))
|
).doOnComplete(ActivationProgressUpdater(ActivationProgress.PHASE_1_COMPLETED))
|
||||||
// TODO these would be common for any observable returned in a public function in this class
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
.doOnNext(PodEventInterceptor()) //
|
.doOnNext(PodEventInterceptor())
|
||||||
.doOnError(ErrorInterceptor())
|
.doOnError(ErrorInterceptor())
|
||||||
.subscribeOn(aapsSchedulers.io)
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
@ -204,12 +245,24 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.PRIMING)) {
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.PRIMING)) {
|
||||||
observables.add(
|
observables.add(
|
||||||
observeSendProgramBolusCommand(
|
Observable.defer {
|
||||||
podStateManager.firstPrimeBolusVolume!! * 0.05,
|
Observable.timer(podStateManager.firstPrimeBolusVolume!!.toLong(), TimeUnit.SECONDS)
|
||||||
podStateManager.primePulseRate!!.toByte(),
|
.flatMap { Observable.empty() }
|
||||||
confirmationBeeps = false,
|
})
|
||||||
completionBeeps = false
|
observables.add(
|
||||||
).doOnComplete(ActivationProgressUpdater(ActivationProgress.PRIMING))
|
Observable.defer {
|
||||||
|
bleManager.sendCommand(
|
||||||
|
ProgramBolusCommand.Builder()
|
||||||
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
|
.setNonce(NONCE)
|
||||||
|
.setNumberOfUnits(podStateManager.firstPrimeBolusVolume!! * 0.05)
|
||||||
|
.setDelayBetweenPulsesInEighthSeconds(podStateManager.primePulseRate!!.toByte())
|
||||||
|
.setProgramReminder(ProgramReminder(atStart = false, atEnd = false, atInterval = 0))
|
||||||
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
|
)
|
||||||
|
}.doOnComplete(ActivationProgressUpdater(ActivationProgress.PRIMING))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.REPROGRAMMED_LUMP_OF_COAL_ALERT)) {
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.REPROGRAMMED_LUMP_OF_COAL_ALERT)) {
|
||||||
|
@ -267,7 +320,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
observeActivationPart2Commands(basalProgram)
|
observeActivationPart2Commands(basalProgram)
|
||||||
).doOnComplete(ActivationProgressUpdater(ActivationProgress.COMPLETED))
|
).doOnComplete(ActivationProgressUpdater(ActivationProgress.COMPLETED))
|
||||||
// TODO these would be common for any observable returned in a public function in this class
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
.doOnNext(PodEventInterceptor()) //
|
.doOnNext(PodEventInterceptor())
|
||||||
.doOnError(ErrorInterceptor())
|
.doOnError(ErrorInterceptor())
|
||||||
.subscribeOn(aapsSchedulers.io)
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
@ -292,6 +345,11 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.INSERTING_CANNULA)) {
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.INSERTING_CANNULA)) {
|
||||||
|
observables.add(
|
||||||
|
Observable.defer {
|
||||||
|
Observable.timer(podStateManager.secondPrimeBolusVolume!!.toLong(), TimeUnit.SECONDS)
|
||||||
|
.flatMap { Observable.empty() }
|
||||||
|
})
|
||||||
observables.add(
|
observables.add(
|
||||||
observeSendProgramBolusCommand(
|
observeSendProgramBolusCommand(
|
||||||
podStateManager.secondPrimeBolusVolume!! * 0.05,
|
podStateManager.secondPrimeBolusVolume!! * 0.05,
|
||||||
|
@ -335,7 +393,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.PROGRAMMED_BASAL)) {
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.PROGRAMMED_BASAL)) {
|
||||||
observables.add(
|
observables.add(
|
||||||
observeProgramBasalCommand(basalProgram)
|
observeSendProgramBasalCommand(basalProgram)
|
||||||
.doOnComplete(ActivationProgressUpdater(ActivationProgress.PROGRAMMED_BASAL))
|
.doOnComplete(ActivationProgressUpdater(ActivationProgress.PROGRAMMED_BASAL))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -343,70 +401,233 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
return observables.reversed()
|
return observables.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStatus(): Observable<PodEvent> {
|
override fun getStatus(type: ResponseType.StatusResponseType): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observeUniqueIdSet,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendGetPodStatusCommand(type)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setBasalProgram(program: BasalProgram): Observable<PodEvent> {
|
override fun setBasalProgram(basalProgram: BasalProgram): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendProgramBasalCommand(basalProgram)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeSendStopDeliveryCommand(deliveryType: StopDeliveryCommand.DeliveryType): Observable<PodEvent> {
|
||||||
|
return Observable.defer {
|
||||||
|
bleManager.sendCommand(
|
||||||
|
StopDeliveryCommand.Builder()
|
||||||
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
|
.setNonce(NONCE)
|
||||||
|
.setDeliveryType(deliveryType)
|
||||||
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun suspendDelivery(): Observable<PodEvent> {
|
override fun suspendDelivery(): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.ALL)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTime(): Observable<PodEvent> {
|
override fun setTime(): Observable<PodEvent> {
|
||||||
// TODO
|
// TODO
|
||||||
|
logger.error(LTag.PUMPCOMM, "NOT IMPLEMENTED: setTime()")
|
||||||
return Observable.empty()
|
return Observable.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeSendProgramTempBasalCommand(rate: Double, durationInMinutes: Short): Observable<PodEvent> {
|
||||||
|
return Observable.defer {
|
||||||
|
// TODO cancel current temp basal (if active)
|
||||||
|
bleManager.sendCommand(
|
||||||
|
ProgramTempBasalCommand.Builder()
|
||||||
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
|
.setNonce(NONCE)
|
||||||
|
.setRateInUnitsPerHour(rate)
|
||||||
|
.setDurationInMinutes(durationInMinutes)
|
||||||
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun setTempBasal(rate: Double, durationInMinutes: Short): Observable<PodEvent> {
|
override fun setTempBasal(rate: Double, durationInMinutes: Short): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendProgramTempBasalCommand(rate, durationInMinutes)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelTempBasal(): Observable<PodEvent> {
|
override fun stopTempBasal(): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.TEMP_BASAL)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bolus(amount: Double): Observable<PodEvent> {
|
override fun bolus(units: Double, confirmationBeeps: Boolean, completionBeeps: Boolean): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendProgramBolusCommand(
|
||||||
|
units,
|
||||||
|
podStateManager.pulseRate!!.toByte(),
|
||||||
|
confirmationBeeps,
|
||||||
|
completionBeeps
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelBolus(): Observable<PodEvent> {
|
override fun stopBolus(): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.BOLUS)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun programBeeps(): Observable<PodEvent> {
|
private fun observeSendConfigureBeepsCommand(
|
||||||
// TODO
|
basalReminder: ProgramReminder = ProgramReminder(atStart = false, atEnd = false, atInterval = 0),
|
||||||
return Observable.empty()
|
tempBasalReminder: ProgramReminder = ProgramReminder(atStart = false, atEnd = false, atInterval = 0),
|
||||||
|
bolusReminder: ProgramReminder = ProgramReminder(atStart = false, atEnd = false, atInterval = 0),
|
||||||
|
immediateBeepType: BeepType = BeepType.SILENT
|
||||||
|
): Observable<PodEvent> {
|
||||||
|
return Observable.defer {
|
||||||
|
bleManager.sendCommand(
|
||||||
|
ProgramBeepsCommand.Builder()
|
||||||
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
|
.setBasalReminder(basalReminder)
|
||||||
|
.setTempBasalReminder(tempBasalReminder)
|
||||||
|
.setBolusReminder(bolusReminder)
|
||||||
|
.setImmediateBeepType(immediateBeepType)
|
||||||
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun playBeep(beepType: BeepType): Observable<PodEvent> {
|
||||||
|
return Observable.concat(
|
||||||
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendConfigureBeepsCommand(immediateBeepType = beepType)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun programAlerts(alertConfigurations: List<AlertConfiguration>): Observable<PodEvent> {
|
override fun programAlerts(alertConfigurations: List<AlertConfiguration>): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendProgramAlertsCommand(alertConfigurations)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun silenceAlerts(alerts: EnumSet<AlertType>): Observable<PodEvent> {
|
private fun observeSendSilenceAlertsCommand(alertTypes: EnumSet<AlertType>): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.defer {
|
||||||
return Observable.empty()
|
bleManager.sendCommand(
|
||||||
|
SilenceAlertsCommand.Builder()
|
||||||
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
|
.setNonce(NONCE)
|
||||||
|
.setAlertTypes(alertTypes)
|
||||||
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun silenceAlerts(alertTypes: EnumSet<AlertType>): Observable<PodEvent> {
|
||||||
|
return Observable.concat(
|
||||||
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendSilenceAlertsCommand(alertTypes)
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val observeSendDeactivateCommand: Observable<PodEvent>
|
||||||
|
get() = Observable.defer {
|
||||||
|
bleManager.sendCommand(
|
||||||
|
DeactivateCommand.Builder()
|
||||||
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
|
.setNonce(NONCE)
|
||||||
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun deactivatePod(): Observable<PodEvent> {
|
override fun deactivatePod(): Observable<PodEvent> {
|
||||||
// TODO
|
return Observable.concat(
|
||||||
return Observable.empty()
|
observePodRunning,
|
||||||
|
observeConnectToPod,
|
||||||
|
observeSendDeactivateCommand
|
||||||
|
)
|
||||||
|
// TODO these would be common for any observable returned in a public function in this class
|
||||||
|
.doOnNext(PodEventInterceptor())
|
||||||
|
.doOnError(ErrorInterceptor())
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
|
//
|
||||||
|
.doOnComplete(podStateManager::reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class PodEventInterceptor : Consumer<PodEvent> {
|
inner class PodEventInterceptor : Consumer<PodEvent> {
|
||||||
|
|
||||||
override fun accept(event: PodEvent) {
|
override fun accept(event: PodEvent) {
|
||||||
logger.debug(LTag.PUMP, "Intercepted PodEvent in OmnipodDashManagerImpl: ${event.javaClass.simpleName}")
|
logger.debug(LTag.PUMP, "Intercepted PodEvent in OmnipodDashManagerImpl: ${event.javaClass.simpleName}")
|
||||||
|
|
||||||
when (event) {
|
when (event) {
|
||||||
is PodEvent.AlreadyConnected -> {
|
is PodEvent.AlreadyConnected -> {
|
||||||
podStateManager.bluetoothAddress = event.bluetoothAddress
|
podStateManager.bluetoothAddress = event.bluetoothAddress
|
||||||
|
|
|
@ -3,11 +3,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status.ConnectionStatus
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status.ConnectionStatus
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
interface OmnipodDashBleManager {
|
interface OmnipodDashBleManager {
|
||||||
|
|
||||||
fun sendCommand(cmd: Command): Observable<PodEvent>
|
fun sendCommand(cmd: Command, responseType: KClass<out Response>): Observable<PodEvent>
|
||||||
|
|
||||||
fun getStatus(): ConnectionStatus
|
fun getStatus(): ConnectionStatus
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,14 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status.ConnectionStatus
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status.ConnectionStatus
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||||
import info.nightscout.androidaps.utils.extensions.toHex
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class OmnipodDashBleManagerImpl @Inject constructor(
|
class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
|
@ -38,49 +40,50 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
private val podId = uniqueId?.let(Id::fromLong)
|
private val podId = uniqueId?.let(Id::fromLong)
|
||||||
?: myId.increment() // pod not activated
|
?: myId.increment() // pod not activated
|
||||||
|
|
||||||
override fun sendCommand(cmd: Command): Observable<PodEvent> = Observable.create { emitter ->
|
override fun sendCommand(cmd: Command, responseType: KClass<out Response>): Observable<PodEvent> =
|
||||||
if (!busy.compareAndSet(false, true)) {
|
Observable.create { emitter ->
|
||||||
throw BusyException()
|
if (!busy.compareAndSet(false, true)) {
|
||||||
}
|
throw BusyException()
|
||||||
try {
|
}
|
||||||
val conn = connection ?: throw NotConnectedException("Not connected")
|
try {
|
||||||
|
val conn = connection ?: throw NotConnectedException("Not connected")
|
||||||
|
|
||||||
val session = conn.session ?: throw NotConnectedException("Missing session")
|
val session = conn.session ?: throw NotConnectedException("Missing session")
|
||||||
|
|
||||||
emitter.onNext(PodEvent.CommandSending(cmd))
|
emitter.onNext(PodEvent.CommandSending(cmd))
|
||||||
|
when (session.sendCommand(cmd)) {
|
||||||
|
is CommandSendErrorSending -> {
|
||||||
|
emitter.tryOnError(CouldNotSendCommandException())
|
||||||
|
return@create
|
||||||
|
}
|
||||||
|
|
||||||
when (session.sendCommand(cmd)) {
|
is CommandSendSuccess ->
|
||||||
is CommandSendErrorSending -> {
|
emitter.onNext(PodEvent.CommandSent(cmd))
|
||||||
emitter.tryOnError(CouldNotSendCommandException())
|
is CommandSendErrorConfirming ->
|
||||||
return@create
|
emitter.onNext(PodEvent.CommandSendNotConfirmed(cmd))
|
||||||
}
|
}
|
||||||
|
|
||||||
is CommandSendSuccess ->
|
when (val readResult = session.readAndAckResponse(responseType)) {
|
||||||
emitter.onNext(PodEvent.CommandSent(cmd))
|
is CommandReceiveSuccess ->
|
||||||
is CommandSendErrorConfirming ->
|
emitter.onNext(PodEvent.ResponseReceived(cmd, readResult.result))
|
||||||
emitter.onNext(PodEvent.CommandSendNotConfirmed(cmd))
|
|
||||||
}
|
|
||||||
|
|
||||||
when (val readResult = session.readAndAckResponse()) {
|
is CommandAckError ->
|
||||||
is CommandReceiveSuccess ->
|
emitter.onNext(PodEvent.ResponseReceived(cmd, readResult.result))
|
||||||
emitter.onNext(PodEvent.ResponseReceived(readResult.result))
|
|
||||||
|
|
||||||
is CommandAckError ->
|
is CommandReceiveError -> {
|
||||||
emitter.onNext(PodEvent.ResponseReceived(readResult.result))
|
emitter.tryOnError(MessageIOException("Could not read response: $readResult"))
|
||||||
|
return@create
|
||||||
is CommandReceiveError -> {
|
}
|
||||||
emitter.tryOnError(MessageIOException("Could not read response: $readResult"))
|
|
||||||
return@create
|
|
||||||
}
|
}
|
||||||
|
emitter.onComplete()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
disconnect()
|
||||||
|
emitter.tryOnError(ex)
|
||||||
|
} finally {
|
||||||
|
busy.set(false)
|
||||||
}
|
}
|
||||||
emitter.onComplete()
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
disconnect()
|
|
||||||
emitter.tryOnError(ex)
|
|
||||||
} finally {
|
|
||||||
busy.set(false)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStatus(): ConnectionStatus {
|
override fun getStatus(): ConnectionStatus {
|
||||||
var s: ConnectionStatus
|
var s: ConnectionStatus
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||||
|
|
||||||
|
class CouldNotParseResponseException(message: String?) : Exception(message)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class IllegalResponseException(
|
||||||
|
expectedResponseType: KClass<out Response>,
|
||||||
|
actualResponse: Response
|
||||||
|
) : Exception("Illegal response: expected ${expectedResponseType.simpleName} but got $actualResponse")
|
|
@ -0,0 +1,5 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.NakResponse
|
||||||
|
|
||||||
|
class NakResponseException(val response: NakResponse) : Exception("Received NAK response: ${response.nakErrorType.value} ${response.nakErrorType.name}")
|
|
@ -0,0 +1,13 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class PodAlarmException(val response: AlarmStatusResponse) : Exception(
|
||||||
|
String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
|
"Pod is in alarm: %03d %s",
|
||||||
|
response.alarmType.value.toInt() and 0xff,
|
||||||
|
response.alarmType.name
|
||||||
|
)
|
||||||
|
)
|
|
@ -0,0 +1,44 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotParseResponseException
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.*
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue
|
||||||
|
|
||||||
|
object ResponseUtil {
|
||||||
|
|
||||||
|
@Throws(CouldNotParseResponseException::class, UnsupportedOperationException::class)
|
||||||
|
fun parseResponse(payload: ByteArray): Response {
|
||||||
|
return when (byValue(payload[0], ResponseType.UNKNOWN)) {
|
||||||
|
ResponseType.ACTIVATION_RESPONSE -> parseActivationResponse(payload)
|
||||||
|
ResponseType.DEFAULT_STATUS_RESPONSE -> DefaultStatusResponse(payload)
|
||||||
|
ResponseType.ADDITIONAL_STATUS_RESPONSE -> parseAdditionalStatusResponse(payload)
|
||||||
|
ResponseType.NAK_RESPONSE -> NakResponse(payload)
|
||||||
|
ResponseType.UNKNOWN -> throw CouldNotParseResponseException("Unrecognized message type: ${payload[0]}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(CouldNotParseResponseException::class)
|
||||||
|
private fun parseActivationResponse(payload: ByteArray): Response {
|
||||||
|
return when (byValue(payload[1], ResponseType.ActivationResponseType.UNKNOWN)) {
|
||||||
|
ResponseType.ActivationResponseType.GET_VERSION_RESPONSE -> VersionResponse(payload)
|
||||||
|
ResponseType.ActivationResponseType.SET_UNIQUE_ID_RESPONSE -> SetUniqueIdResponse(payload)
|
||||||
|
ResponseType.ActivationResponseType.UNKNOWN -> throw CouldNotParseResponseException("Unrecognized activation response type: ${payload[1]}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(CouldNotParseResponseException::class, UnsupportedOperationException::class)
|
||||||
|
private fun parseAdditionalStatusResponse(payload: ByteArray): Response {
|
||||||
|
return when (byValue(payload[2], ResponseType.StatusResponseType.UNKNOWN)) {
|
||||||
|
ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE -> DefaultStatusResponse(payload) // Unreachable; this response type is only used for requesting a default status response
|
||||||
|
ResponseType.StatusResponseType.STATUS_RESPONSE_PAGE_1 -> throw UnsupportedOperationException("Status response page 1 is not (yet) implemented")
|
||||||
|
ResponseType.StatusResponseType.ALARM_STATUS -> AlarmStatusResponse(payload)
|
||||||
|
ResponseType.StatusResponseType.STATUS_RESPONSE_PAGE_3 -> throw UnsupportedOperationException("Status response page 3 is not (yet) implemented")
|
||||||
|
ResponseType.StatusResponseType.STATUS_RESPONSE_PAGE_5 -> throw UnsupportedOperationException("Status response page 5 is not (yet) implemented")
|
||||||
|
ResponseType.StatusResponseType.STATUS_RESPONSE_PAGE_6 -> throw UnsupportedOperationException("Status response page 6 is not (yet) implemented")
|
||||||
|
ResponseType.StatusResponseType.STATUS_RESPONSE_PAGE_70 -> throw UnsupportedOperationException("Status response page 70 is not (yet) implemented")
|
||||||
|
ResponseType.StatusResponseType.STATUS_RESPONSE_PAGE_80 -> throw UnsupportedOperationException("Status response page 80 is not (yet) implemented")
|
||||||
|
ResponseType.StatusResponseType.STATUS_RESPONSE_PAGE_81 -> throw UnsupportedOperationException("Status response page 81 is not (yet) implemented")
|
||||||
|
ResponseType.StatusResponseType.UNKNOWN -> throw CouldNotParseResponseException("Unrecognized additional status response type: ${payload[2]}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,12 +4,18 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.EnDecrypt
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.EnDecrypt
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotParseResponseException
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.IllegalResponseException
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.NakResponseException
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.PodAlarmException
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.*
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.*
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding.Companion.parseKeys
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding.Companion.parseKeys
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.NakResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.NakResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response
|
||||||
import info.nightscout.androidaps.utils.extensions.toHex
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
sealed class CommandSendResult
|
sealed class CommandSendResult
|
||||||
object CommandSendSuccess : CommandSendResult()
|
object CommandSendSuccess : CommandSendResult()
|
||||||
|
@ -36,6 +42,7 @@ class Session(
|
||||||
sessionKeys.msgSequenceNumber++
|
sessionKeys.msgSequenceNumber++
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command: ${cmd.encoded.toHex()} in packet $cmd")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command: ${cmd.encoded.toHex()} in packet $cmd")
|
||||||
var tries = 0
|
var tries = 0
|
||||||
|
|
||||||
val msg = getCmdMessage(cmd)
|
val msg = getCmdMessage(cmd)
|
||||||
var possiblyUnconfirmedCommand = false
|
var possiblyUnconfirmedCommand = false
|
||||||
for (i in 0..MAX_TRIES) {
|
for (i in 0..MAX_TRIES) {
|
||||||
|
@ -62,7 +69,7 @@ class Session(
|
||||||
CommandSendErrorSending(errMsg)
|
CommandSendErrorSending(errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readAndAckResponse(): CommandReceiveResult {
|
fun readAndAckResponse(responseType: KClass<out Response>): CommandReceiveResult {
|
||||||
var responseMsgPacket: MessagePacket? = null
|
var responseMsgPacket: MessagePacket? = null
|
||||||
for (i in 0..MAX_TRIES) {
|
for (i in 0..MAX_TRIES) {
|
||||||
val responseMsg = msgIO.receiveMessage()
|
val responseMsg = msgIO.receiveMessage()
|
||||||
|
@ -78,8 +85,19 @@ class Session(
|
||||||
|
|
||||||
val decrypted = enDecrypt.decrypt(responseMsgPacket)
|
val decrypted = enDecrypt.decrypt(responseMsgPacket)
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Received response: $decrypted")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Received response: $decrypted")
|
||||||
|
|
||||||
val response = parseResponse(decrypted)
|
val response = parseResponse(decrypted)
|
||||||
|
|
||||||
|
if (!responseType.isInstance(response)) {
|
||||||
|
if (response is AlarmStatusResponse) {
|
||||||
|
throw PodAlarmException(response)
|
||||||
|
}
|
||||||
|
if (response is NakResponse) {
|
||||||
|
throw NakResponseException(response)
|
||||||
|
}
|
||||||
|
throw IllegalResponseException(responseType, response)
|
||||||
|
}
|
||||||
|
|
||||||
sessionKeys.msgSequenceNumber++
|
sessionKeys.msgSequenceNumber++
|
||||||
val ack = getAck(responseMsgPacket)
|
val ack = getAck(responseMsgPacket)
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending ACK: ${ack.payload.toHex()} in packet $ack")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending ACK: ${ack.payload.toHex()} in packet $ack")
|
||||||
|
@ -90,11 +108,22 @@ class Session(
|
||||||
return CommandReceiveSuccess(response)
|
return CommandReceiveSuccess(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(CouldNotParseResponseException::class, UnsupportedOperationException::class)
|
||||||
private fun parseResponse(decrypted: MessagePacket): Response {
|
private fun parseResponse(decrypted: MessagePacket): Response {
|
||||||
|
|
||||||
val payload = parseKeys(arrayOf(RESPONSE_PREFIX), decrypted.payload)[0]
|
val data = parseKeys(arrayOf(RESPONSE_PREFIX), decrypted.payload)[0]
|
||||||
aapsLogger.info(LTag.PUMPBTCOMM, "Received decrypted response: ${payload.toHex()} in packet: $decrypted")
|
aapsLogger.info(LTag.PUMPBTCOMM, "Received decrypted response: ${data.toHex()} in packet: $decrypted")
|
||||||
return NakResponse(payload)
|
|
||||||
|
// TODO verify length
|
||||||
|
|
||||||
|
val uniqueId = data.copyOfRange(0, 4)
|
||||||
|
val lenghtAndSequenceNumber = data.copyOfRange(4, 6)
|
||||||
|
val payload = data.copyOfRange(6, data.size - 2)
|
||||||
|
val crc = data.copyOfRange(data.size - 2, data.size)
|
||||||
|
|
||||||
|
// TODO validate uniqueId, sequenceNumber and crc
|
||||||
|
|
||||||
|
return ResponseUtil.parseResponse(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAck(response: MessagePacket): MessagePacket {
|
private fun getAck(response: MessagePacket): MessagePacket {
|
||||||
|
|
|
@ -101,7 +101,7 @@ class SessionEstablisher(
|
||||||
if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) {
|
if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) {
|
||||||
throw SessionEstablishmentException(
|
throw SessionEstablishmentException(
|
||||||
"Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${
|
"Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${
|
||||||
eapMsg.attributes[0].toByteArray().toHex()
|
eapMsg.attributes[0].toByteArray().toHex()
|
||||||
}"
|
}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,20 +7,63 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.
|
||||||
sealed class PodEvent {
|
sealed class PodEvent {
|
||||||
|
|
||||||
/* BT connection events */
|
/* BT connection events */
|
||||||
class AlreadyConnected(val bluetoothAddress: String) : PodEvent()
|
class AlreadyConnected(val bluetoothAddress: String) : PodEvent() {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "AlreadyConnected(bluetoothAddress='$bluetoothAddress')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object AlreadyPaired : PodEvent()
|
object AlreadyPaired : PodEvent()
|
||||||
object Scanning : PodEvent()
|
object Scanning : PodEvent()
|
||||||
object BluetoothConnecting : PodEvent()
|
object BluetoothConnecting : PodEvent()
|
||||||
class BluetoothConnected(val bluetoothAddress: String) : PodEvent()
|
class BluetoothConnected(val bluetoothAddress: String) : PodEvent() {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "BluetoothConnected(bluetoothAddress='$bluetoothAddress')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object Pairing : PodEvent()
|
object Pairing : PodEvent()
|
||||||
class Paired(val uniqueId: Id) : PodEvent()
|
class Paired(val uniqueId: Id) : PodEvent() {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Paired(uniqueId=$uniqueId)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object EstablishingSession : PodEvent()
|
object EstablishingSession : PodEvent()
|
||||||
object Connected : PodEvent()
|
object Connected : PodEvent()
|
||||||
|
|
||||||
/* Message exchange events */
|
/* Message exchange events */
|
||||||
class CommandSending(val command: Command) : PodEvent()
|
class CommandSending(val command: Command) : PodEvent() {
|
||||||
class CommandSent(val command: Command) : PodEvent()
|
|
||||||
class CommandSendNotConfirmed(val command: Command) : PodEvent()
|
|
||||||
|
|
||||||
class ResponseReceived(val response: Response) : PodEvent()
|
override fun toString(): String {
|
||||||
|
return "CommandSending(command=$command)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommandSent(val command: Command) : PodEvent() {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "CommandSent(command=$command)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommandSendNotConfirmed(val command: Command) : PodEvent() {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "CommandSentNotConfirmed(command=$command)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResponseReceived(
|
||||||
|
val command: Command,
|
||||||
|
val response: Response
|
||||||
|
) : PodEvent() {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ResponseReceived(command=$command, response=$response)"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ class DeactivateCommand private constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() = appendCrc(
|
get() = appendCrc(
|
||||||
ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
ByteBuffer.allocate(LENGTH + HEADER_LENGTH)
|
||||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag))
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(BODY_LENGTH) //
|
.put(BODY_LENGTH)
|
||||||
.putInt(nonce) //
|
.putInt(nonce)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,11 @@ class GetStatusCommand private constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() = appendCrc(
|
get() = appendCrc(
|
||||||
ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
ByteBuffer.allocate(LENGTH + HEADER_LENGTH)
|
||||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag))
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(BODY_LENGTH) //
|
.put(BODY_LENGTH)
|
||||||
.put(statusResponseType.value) //
|
.put(statusResponseType.value)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,11 @@ class GetVersionCommand private constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() = appendCrc(
|
get() = appendCrc(
|
||||||
ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
ByteBuffer.allocate(LENGTH + HEADER_LENGTH)
|
||||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag))
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(BODY_LENGTH) //
|
.put(BODY_LENGTH)
|
||||||
.putInt(uniqueId) //
|
.putInt(uniqueId)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,10 @@ class ProgramAlertsCommand private constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() {
|
get() {
|
||||||
val byteBuffer: ByteBuffer = ByteBuffer.allocate(getLength() + HEADER_LENGTH) //
|
val byteBuffer: ByteBuffer = ByteBuffer.allocate(getLength() + HEADER_LENGTH)
|
||||||
.put(encodeHeader(uniqueId, sequenceNumber, getLength(), multiCommandFlag)) //
|
.put(encodeHeader(uniqueId, sequenceNumber, getLength(), multiCommandFlag))
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(getBodyLength()) //
|
.put(getBodyLength())
|
||||||
.putInt(nonce)
|
.putInt(nonce)
|
||||||
for (configuration in alertConfigurations) {
|
for (configuration in alertConfigurations) {
|
||||||
byteBuffer.put(configuration.encoded)
|
byteBuffer.put(configuration.encoded)
|
||||||
|
|
|
@ -36,12 +36,12 @@ class ProgramBasalCommand private constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() {
|
get() {
|
||||||
val buffer = ByteBuffer.allocate(length.toInt()) //
|
val buffer = ByteBuffer.allocate(length.toInt())
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(bodyLength) //
|
.put(bodyLength)
|
||||||
.put(programReminder.encoded) //
|
.put(programReminder.encoded)
|
||||||
.put(currentInsulinProgramElementIndex) //
|
.put(currentInsulinProgramElementIndex)
|
||||||
.putShort(remainingTenthPulsesInCurrentInsulinProgramElement) //
|
.putShort(remainingTenthPulsesInCurrentInsulinProgramElement)
|
||||||
.putInt(delayUntilNextTenthPulseInUsec)
|
.putInt(delayUntilNextTenthPulseInUsec)
|
||||||
for (insulinProgramElement in insulinProgramElements) {
|
for (insulinProgramElement in insulinProgramElements) {
|
||||||
buffer.put(insulinProgramElement.encoded)
|
buffer.put(insulinProgramElement.encoded)
|
||||||
|
@ -55,10 +55,10 @@ class ProgramBasalCommand private constructor(
|
||||||
multiCommandFlag
|
multiCommandFlag
|
||||||
)
|
)
|
||||||
return appendCrc(
|
return appendCrc(
|
||||||
ByteBuffer.allocate(basalCommand.size + interlockCommand.size + header.size) //
|
ByteBuffer.allocate(basalCommand.size + interlockCommand.size + header.size)
|
||||||
.put(header) //
|
.put(header)
|
||||||
.put(interlockCommand) //
|
.put(interlockCommand)
|
||||||
.put(basalCommand) //
|
.put(basalCommand)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,14 @@ class ProgramBeepsCommand private constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() = appendCrc(
|
get() = appendCrc(
|
||||||
ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
ByteBuffer.allocate(LENGTH + HEADER_LENGTH)
|
||||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag))
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(BODY_LENGTH) //
|
.put(BODY_LENGTH)
|
||||||
.put(immediateBeepType.value) //
|
.put(immediateBeepType.value)
|
||||||
.put(basalReminder.encoded) //
|
.put(basalReminder.encoded)
|
||||||
.put(tempBasalReminder.encoded) //
|
.put(tempBasalReminder.encoded)
|
||||||
.put(bolusReminder.encoded) //
|
.put(bolusReminder.encoded)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,12 @@ class ProgramBolusCommand private constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() {
|
get() {
|
||||||
val bolusCommand = ByteBuffer.allocate(LENGTH.toInt()) //
|
val bolusCommand = ByteBuffer.allocate(LENGTH.toInt())
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(BODY_LENGTH) //
|
.put(BODY_LENGTH)
|
||||||
.put(programReminder.encoded) //
|
.put(programReminder.encoded)
|
||||||
.putShort(numberOfTenthPulses) //
|
.putShort(numberOfTenthPulses)
|
||||||
.putInt(delayUntilFirstTenthPulseInUsec) //
|
.putInt(delayUntilFirstTenthPulseInUsec)
|
||||||
.putShort(0.toShort()) // Extended bolus pulses
|
.putShort(0.toShort()) // Extended bolus pulses
|
||||||
.putInt(0) // Delay between tenth extended pulses in usec
|
.putInt(0) // Delay between tenth extended pulses in usec
|
||||||
.array()
|
.array()
|
||||||
|
@ -38,10 +38,10 @@ class ProgramBolusCommand private constructor(
|
||||||
multiCommandFlag
|
multiCommandFlag
|
||||||
)
|
)
|
||||||
return appendCrc(
|
return appendCrc(
|
||||||
ByteBuffer.allocate(header.size + interlockCommand.size + bolusCommand.size) //
|
ByteBuffer.allocate(header.size + interlockCommand.size + bolusCommand.size)
|
||||||
.put(header) //
|
.put(header)
|
||||||
.put(interlockCommand) //
|
.put(interlockCommand)
|
||||||
.put(bolusCommand) //
|
.put(bolusCommand)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -120,11 +120,11 @@ class ProgramBolusCommand private constructor(
|
||||||
private const val BODY_LENGTH: Byte = 13
|
private const val BODY_LENGTH: Byte = 13
|
||||||
private fun calculateChecksum(numberOfSlots: Byte, byte10And11: Short, numberOfPulses: Short): Short {
|
private fun calculateChecksum(numberOfSlots: Byte, byte10And11: Short, numberOfPulses: Short): Short {
|
||||||
return MessageUtil.calculateChecksum(
|
return MessageUtil.calculateChecksum(
|
||||||
ByteBuffer.allocate(7) //
|
ByteBuffer.allocate(7)
|
||||||
.put(numberOfSlots) //
|
.put(numberOfSlots)
|
||||||
.putShort(byte10And11) //
|
.putShort(byte10And11)
|
||||||
.putShort(numberOfPulses) //
|
.putShort(numberOfPulses)
|
||||||
.putShort(numberOfPulses) //
|
.putShort(numberOfPulses)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class ProgramInsulinCommand internal constructor(
|
||||||
multiCommandFlag: Boolean,
|
multiCommandFlag: Boolean,
|
||||||
nonce: Int,
|
nonce: Int,
|
||||||
insulinProgramElements:
|
insulinProgramElements:
|
||||||
List<ShortInsulinProgramElement>,
|
List<ShortInsulinProgramElement>,
|
||||||
private val checksum: Short,
|
private val checksum: Short,
|
||||||
private val byte9: Byte,
|
private val byte9: Byte,
|
||||||
private val byte10And11: Short,
|
private val byte10And11: Short,
|
||||||
|
@ -37,12 +37,12 @@ class ProgramInsulinCommand internal constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() {
|
get() {
|
||||||
val buffer = ByteBuffer.allocate(getLength().toInt()) //
|
val buffer = ByteBuffer.allocate(getLength().toInt())
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(getBodyLength()) //
|
.put(getBodyLength())
|
||||||
.putInt(nonce) //
|
.putInt(nonce)
|
||||||
.put(deliveryType.getValue()) //
|
.put(deliveryType.getValue())
|
||||||
.putShort(checksum) //
|
.putShort(checksum)
|
||||||
.put(byte9) // BASAL: currentSlot // BOLUS: number of ShortInsulinProgramElements
|
.put(byte9) // BASAL: currentSlot // BOLUS: number of ShortInsulinProgramElements
|
||||||
.putShort(byte10And11) // BASAL: remainingEighthSecondsInCurrentSlot // BOLUS: immediate pulses multiplied by delay between pulses in eighth seconds
|
.putShort(byte10And11) // BASAL: remainingEighthSecondsInCurrentSlot // BOLUS: immediate pulses multiplied by delay between pulses in eighth seconds
|
||||||
.putShort(byte12And13) // BASAL: remainingPulsesInCurrentSlot // BOLUS: immediate pulses
|
.putShort(byte12And13) // BASAL: remainingPulsesInCurrentSlot // BOLUS: immediate pulses
|
||||||
|
|
|
@ -103,12 +103,12 @@ class ProgramTempBasalCommand private constructor(
|
||||||
delayUntilNextTenthPulseInUsec =
|
delayUntilNextTenthPulseInUsec =
|
||||||
(firstProgramElement.numberOfSlots.toLong() * 1800.0 / remainingTenthPulsesInFirstElement * 1000000).toInt()
|
(firstProgramElement.numberOfSlots.toLong() * 1800.0 / remainingTenthPulsesInFirstElement * 1000000).toInt()
|
||||||
}
|
}
|
||||||
val buffer = ByteBuffer.allocate(getLength().toInt()) //
|
val buffer = ByteBuffer.allocate(getLength().toInt())
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(getBodyLength()) //
|
.put(getBodyLength())
|
||||||
.put(programReminder.encoded) //
|
.put(programReminder.encoded)
|
||||||
.put(0x00.toByte()) // Current slot index
|
.put(0x00.toByte()) // Current slot index
|
||||||
.putShort(remainingTenthPulsesInFirstElement) //
|
.putShort(remainingTenthPulsesInFirstElement)
|
||||||
.putInt(delayUntilNextTenthPulseInUsec)
|
.putInt(delayUntilNextTenthPulseInUsec)
|
||||||
for (element in insulinProgramElements) {
|
for (element in insulinProgramElements) {
|
||||||
buffer.put(element.encoded)
|
buffer.put(element.encoded)
|
||||||
|
@ -122,10 +122,10 @@ class ProgramTempBasalCommand private constructor(
|
||||||
multiCommandFlag
|
multiCommandFlag
|
||||||
)
|
)
|
||||||
return appendCrc(
|
return appendCrc(
|
||||||
ByteBuffer.allocate(header.size + interlockCommand.size + tempBasalCommand.size) //
|
ByteBuffer.allocate(header.size + interlockCommand.size + tempBasalCommand.size)
|
||||||
.put(header) //
|
.put(header)
|
||||||
.put(interlockCommand) //
|
.put(interlockCommand)
|
||||||
.put(tempBasalCommand) //
|
.put(tempBasalCommand)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,16 +17,16 @@ class SetUniqueIdCommand private constructor(
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() = appendCrc(
|
get() = appendCrc(
|
||||||
ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
ByteBuffer.allocate(LENGTH + HEADER_LENGTH)
|
||||||
.put(encodeHeader(DEFAULT_UNIQUE_ID, sequenceNumber, LENGTH, multiCommandFlag)) //
|
.put(encodeHeader(DEFAULT_UNIQUE_ID, sequenceNumber, LENGTH, multiCommandFlag))
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(BODY_LENGTH) //
|
.put(BODY_LENGTH)
|
||||||
.putInt(uniqueId) //
|
.putInt(uniqueId)
|
||||||
.put(0x14.toByte()) // FIXME ??
|
.put(0x14.toByte()) // FIXME ??
|
||||||
.put(0x04.toByte()) // FIXME ??
|
.put(0x04.toByte()) // FIXME ??
|
||||||
.put(encodeInitializationTime(initializationTime)) //
|
.put(encodeInitializationTime(initializationTime))
|
||||||
.putInt(lotNumber) //
|
.putInt(lotNumber)
|
||||||
.putInt(podSequenceNumber) //
|
.putInt(podSequenceNumber)
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -86,12 +86,12 @@ class SetUniqueIdCommand private constructor(
|
||||||
private fun encodeInitializationTime(date: Date): ByteArray {
|
private fun encodeInitializationTime(date: Date): ByteArray {
|
||||||
val instance = Calendar.getInstance()
|
val instance = Calendar.getInstance()
|
||||||
instance.time = date
|
instance.time = date
|
||||||
return byteArrayOf( //
|
return byteArrayOf(
|
||||||
(instance[Calendar.MONTH] + 1).toByte(), //
|
(instance[Calendar.MONTH] + 1).toByte(),
|
||||||
instance[Calendar.DATE].toByte(), //
|
instance[Calendar.DATE].toByte(),
|
||||||
(instance[Calendar.YEAR] % 100).toByte(), //
|
(instance[Calendar.YEAR] % 100).toByte(),
|
||||||
instance[Calendar.HOUR_OF_DAY].toByte(), //
|
instance[Calendar.HOUR_OF_DAY].toByte(),
|
||||||
instance[Calendar.MINUTE].toByte() //
|
instance[Calendar.MINUTE].toByte()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,12 @@ class SilenceAlertsCommand private constructor(
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() =
|
get() =
|
||||||
appendCrc(
|
appendCrc(
|
||||||
ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
ByteBuffer.allocate(LENGTH + HEADER_LENGTH)
|
||||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag))
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(BODY_LENGTH) //
|
.put(BODY_LENGTH)
|
||||||
.putInt(nonce) //
|
.putInt(nonce)
|
||||||
.put(AlertUtil.encodeAlertSet(alertTypes)) //
|
.put(AlertUtil.encodeAlertSet(alertTypes))
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,12 @@ class StopDeliveryCommand private constructor(
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() {
|
get() {
|
||||||
return appendCrc(
|
return appendCrc(
|
||||||
ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
ByteBuffer.allocate(LENGTH + HEADER_LENGTH)
|
||||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag))
|
||||||
.put(commandType.value) //
|
.put(commandType.value)
|
||||||
.put(BODY_LENGTH) //
|
.put(BODY_LENGTH)
|
||||||
.putInt(nonce) //
|
.putInt(nonce)
|
||||||
.put((beepType.value.toInt() shl 4 or deliveryType.encoded[0].toInt()).toByte()) //
|
.put((beepType.value.toInt() shl 4 or deliveryType.encoded[0].toInt()).toByte())
|
||||||
.array()
|
.array()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ abstract class HeaderEnabledCommand protected constructor(
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
internal fun appendCrc(command: ByteArray): ByteArray =
|
internal fun appendCrc(command: ByteArray): ByteArray =
|
||||||
ByteBuffer.allocate(command.size + 2) //
|
ByteBuffer.allocate(command.size + 2)
|
||||||
.put(command) //
|
.put(command)
|
||||||
.putShort(MessageUtil.createCrc(command)) //
|
.putShort(MessageUtil.createCrc(command))
|
||||||
.array()
|
.array()
|
||||||
|
|
||||||
internal fun encodeHeader(
|
internal fun encodeHeader(
|
||||||
|
@ -24,9 +24,9 @@ abstract class HeaderEnabledCommand protected constructor(
|
||||||
length: Short,
|
length: Short,
|
||||||
multiCommandFlag: Boolean
|
multiCommandFlag: Boolean
|
||||||
): ByteArray =
|
): ByteArray =
|
||||||
ByteBuffer.allocate(6) //
|
ByteBuffer.allocate(6)
|
||||||
.putInt(uniqueId) //
|
.putInt(uniqueId)
|
||||||
.putShort((sequenceNumber.toInt() and 0x0f shl 10 or length.toInt() or ((if (multiCommandFlag) 1 else 0) shl 15)).toShort()) //
|
.putShort((sequenceNumber.toInt() and 0x0f shl 10 or length.toInt() or ((if (multiCommandFlag) 1 else 0) shl 15)).toShort())
|
||||||
.array()
|
.array()
|
||||||
|
|
||||||
internal const val HEADER_LENGTH: Short = 6
|
internal const val HEADER_LENGTH: Short = 6
|
||||||
|
|
|
@ -12,9 +12,9 @@ open class BasalInsulinProgramElement(
|
||||||
) : Encodable, Serializable {
|
) : Encodable, Serializable {
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() = ByteBuffer.allocate(6) //
|
get() = ByteBuffer.allocate(6)
|
||||||
.putShort(totalTenthPulses) //
|
.putShort(totalTenthPulses)
|
||||||
.putInt(if (totalTenthPulses.toInt() == 0) Int.MIN_VALUE or delayBetweenTenthPulsesInUsec else delayBetweenTenthPulsesInUsec) //
|
.putInt(if (totalTenthPulses.toInt() == 0) Int.MIN_VALUE or delayBetweenTenthPulsesInUsec else delayBetweenTenthPulsesInUsec)
|
||||||
.array()
|
.array()
|
||||||
val durationInSeconds: Short
|
val durationInSeconds: Short
|
||||||
get() = (numberOfSlots * 1800).toShort()
|
get() = (numberOfSlots * 1800).toShort()
|
||||||
|
|
|
@ -12,13 +12,13 @@ class BasalShortInsulinProgramElement(
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
get() {
|
get() {
|
||||||
val firstByte = (
|
val firstByte = (
|
||||||
numberOfSlots - 1 and 0x0f shl 4 //
|
numberOfSlots - 1 and 0x0f shl 4
|
||||||
or ((if (extraAlternatePulse) 1 else 0) shl 3) //
|
or ((if (extraAlternatePulse) 1 else 0) shl 3)
|
||||||
or (pulsesPerSlot.toInt() ushr 8 and 0x03)
|
or (pulsesPerSlot.toInt() ushr 8 and 0x03)
|
||||||
).toByte()
|
).toByte()
|
||||||
return ByteBuffer.allocate(2) //
|
return ByteBuffer.allocate(2)
|
||||||
.put(firstByte) //
|
.put(firstByte)
|
||||||
.put((pulsesPerSlot and 0xff).toByte()) //
|
.put((pulsesPerSlot and 0xff).toByte())
|
||||||
.array()
|
.array()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@ class TempBasalInsulinProgramElement(
|
||||||
val buffer = ByteBuffer.allocate(6)
|
val buffer = ByteBuffer.allocate(6)
|
||||||
if (totalTenthPulses.toInt() == 0) {
|
if (totalTenthPulses.toInt() == 0) {
|
||||||
val i = (durationInSeconds.toDouble() * 1000000.0 / numberOfSlots.toDouble()).toInt() or Int.MIN_VALUE
|
val i = (durationInSeconds.toDouble() * 1000000.0 / numberOfSlots.toDouble()).toInt() or Int.MIN_VALUE
|
||||||
buffer.putShort(numberOfSlots.toShort()) //
|
buffer.putShort(numberOfSlots.toShort())
|
||||||
.putInt(i)
|
.putInt(i)
|
||||||
} else {
|
} else {
|
||||||
buffer.putShort(totalTenthPulses) //
|
buffer.putShort(totalTenthPulses)
|
||||||
.putInt(delayBetweenTenthPulsesInUsec)
|
.putInt(delayBetweenTenthPulsesInUsec)
|
||||||
}
|
}
|
||||||
return buffer.array()
|
return buffer.array()
|
||||||
|
|
|
@ -56,6 +56,7 @@ object ProgramBasalUtil {
|
||||||
|
|
||||||
fun mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot: ShortArray?): List<ShortInsulinProgramElement> {
|
fun mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot: ShortArray?): List<ShortInsulinProgramElement> {
|
||||||
require(pulsesPerSlot!!.size <= NUMBER_OF_BASAL_SLOTS) { "Basal program must contain at most 48 slots" }
|
require(pulsesPerSlot!!.size <= NUMBER_OF_BASAL_SLOTS) { "Basal program must contain at most 48 slots" }
|
||||||
|
|
||||||
val elements: MutableList<ShortInsulinProgramElement> = ArrayList()
|
val elements: MutableList<ShortInsulinProgramElement> = ArrayList()
|
||||||
var extraAlternatePulse = false
|
var extraAlternatePulse = false
|
||||||
var previousPulsesPerSlot: Short = 0
|
var previousPulsesPerSlot: Short = 0
|
||||||
|
@ -84,7 +85,7 @@ object ProgramBasalUtil {
|
||||||
extraAlternatePulse = false
|
extraAlternatePulse = false
|
||||||
}
|
}
|
||||||
currentTotalNumberOfSlots++
|
currentTotalNumberOfSlots++
|
||||||
} else if (numberOfSlotsInCurrentElement.toInt() == 1 && pulsesPerSlot[currentTotalNumberOfSlots.toInt()].toInt() == previousPulsesPerSlot + 1) {
|
} else if (numberOfSlotsInCurrentElement.toInt() == 1 && !extraAlternatePulse && pulsesPerSlot[currentTotalNumberOfSlots.toInt()].toInt() == previousPulsesPerSlot + 1) {
|
||||||
// Second slot of segment with extra alternate pulse
|
// Second slot of segment with extra alternate pulse
|
||||||
var expectAlternatePulseForNextSegment = false
|
var expectAlternatePulseForNextSegment = false
|
||||||
currentTotalNumberOfSlots++
|
currentTotalNumberOfSlots++
|
||||||
|
@ -94,10 +95,10 @@ object ProgramBasalUtil {
|
||||||
// Loop rest alternate pulse segment
|
// Loop rest alternate pulse segment
|
||||||
if (pulsesPerSlot[currentTotalNumberOfSlots.toInt()].toInt() == previousPulsesPerSlot + (if (expectAlternatePulseForNextSegment) 1 else 0)) {
|
if (pulsesPerSlot[currentTotalNumberOfSlots.toInt()].toInt() == previousPulsesPerSlot + (if (expectAlternatePulseForNextSegment) 1 else 0)) {
|
||||||
// Still in alternate pulse segment
|
// Still in alternate pulse segment
|
||||||
currentTotalNumberOfSlots++
|
|
||||||
expectAlternatePulseForNextSegment = !expectAlternatePulseForNextSegment
|
expectAlternatePulseForNextSegment = !expectAlternatePulseForNextSegment
|
||||||
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||||
numberOfSlotsInCurrentElement++
|
numberOfSlotsInCurrentElement++
|
||||||
|
currentTotalNumberOfSlots++
|
||||||
} else {
|
} else {
|
||||||
// End of alternate pulse segment (no slots left in element)
|
// End of alternate pulse segment (no slots left in element)
|
||||||
elements.add(
|
elements.add(
|
||||||
|
@ -110,6 +111,7 @@ object ProgramBasalUtil {
|
||||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||||
numberOfSlotsInCurrentElement = 1
|
numberOfSlotsInCurrentElement = 1
|
||||||
extraAlternatePulse = false
|
extraAlternatePulse = false
|
||||||
|
currentTotalNumberOfSlots++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -193,6 +195,7 @@ object ProgramBasalUtil {
|
||||||
val hourOfDay = instance[Calendar.HOUR_OF_DAY]
|
val hourOfDay = instance[Calendar.HOUR_OF_DAY]
|
||||||
val minuteOfHour = instance[Calendar.MINUTE]
|
val minuteOfHour = instance[Calendar.MINUTE]
|
||||||
val secondOfMinute = instance[Calendar.SECOND]
|
val secondOfMinute = instance[Calendar.SECOND]
|
||||||
|
|
||||||
val index = ((hourOfDay * 60 + minuteOfHour) / 30).toByte()
|
val index = ((hourOfDay * 60 + minuteOfHour) / 30).toByte()
|
||||||
val secondOfDay = secondOfMinute + hourOfDay * 3600 + minuteOfHour * 60
|
val secondOfDay = secondOfMinute + hourOfDay * 3600 + minuteOfHour * 60
|
||||||
val secondsRemaining = ((index + 1) * 1800 - secondOfDay).toShort()
|
val secondsRemaining = ((index + 1) * 1800 - secondOfDay).toShort()
|
||||||
|
@ -245,9 +248,9 @@ object ProgramBasalUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateChecksum(pulsesPerSlot: ShortArray?, currentSlot: CurrentSlot): Short {
|
fun calculateChecksum(pulsesPerSlot: ShortArray?, currentSlot: CurrentSlot): Short {
|
||||||
val buffer = ByteBuffer.allocate(1 + 2 + 2 + NUMBER_OF_BASAL_SLOTS * 2) //
|
val buffer = ByteBuffer.allocate(1 + 2 + 2 + NUMBER_OF_BASAL_SLOTS * 2)
|
||||||
.put(currentSlot.index) //
|
.put(currentSlot.index)
|
||||||
.putShort(currentSlot.pulsesRemaining) //
|
.putShort(currentSlot.pulsesRemaining)
|
||||||
.putShort(currentSlot.eighthSecondsRemaining)
|
.putShort(currentSlot.eighthSecondsRemaining)
|
||||||
for (pulses in pulsesPerSlot!!) {
|
for (pulses in pulsesPerSlot!!) {
|
||||||
buffer.putShort(pulses)
|
buffer.putShort(pulses)
|
||||||
|
|
|
@ -53,9 +53,9 @@ object ProgramTempBasalUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateChecksum(totalNumberOfSlots: Byte, pulsesInFirstSlot: Short, pulsesPerSlot: ShortArray?): Short {
|
fun calculateChecksum(totalNumberOfSlots: Byte, pulsesInFirstSlot: Short, pulsesPerSlot: ShortArray?): Short {
|
||||||
val buffer = ByteBuffer.allocate(1 + 2 + 2 + 2 * pulsesPerSlot!!.size) //
|
val buffer = ByteBuffer.allocate(1 + 2 + 2 + 2 * pulsesPerSlot!!.size)
|
||||||
.put(totalNumberOfSlots) //
|
.put(totalNumberOfSlots)
|
||||||
.putShort(0x3840.toShort()) //
|
.putShort(0x3840.toShort())
|
||||||
.putShort(pulsesInFirstSlot)
|
.putShort(pulsesInFirstSlot)
|
||||||
for (pulses in pulsesPerSlot) {
|
for (pulses in pulsesPerSlot) {
|
||||||
buffer.putShort(pulses)
|
buffer.putShort(pulses)
|
||||||
|
|
|
@ -26,9 +26,9 @@ class AlertConfiguration(
|
||||||
firstByte = firstByte or (1 shl 1)
|
firstByte = firstByte or (1 shl 1)
|
||||||
}
|
}
|
||||||
firstByte = firstByte or ((durationInMinutes.toInt() shr 8 and 0x01).toByte())
|
firstByte = firstByte or ((durationInMinutes.toInt() shr 8 and 0x01).toByte())
|
||||||
return ByteBuffer.allocate(6) //
|
return ByteBuffer.allocate(6)
|
||||||
.put(firstByte)
|
.put(firstByte)
|
||||||
.put(durationInMinutes.toByte()) //
|
.put(durationInMinutes.toByte())
|
||||||
.putShort(
|
.putShort(
|
||||||
when (trigger) {
|
when (trigger) {
|
||||||
is AlertTrigger.ReservoirVolumeTrigger -> {
|
is AlertTrigger.ReservoirVolumeTrigger -> {
|
||||||
|
@ -39,9 +39,9 @@ class AlertConfiguration(
|
||||||
trigger.offsetInMinutes
|
trigger.offsetInMinutes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) //
|
)
|
||||||
.put(beepRepetition.value) //
|
.put(beepRepetition.value)
|
||||||
.put(beepType.value) //
|
.put(beepType.value)
|
||||||
.array()
|
.array()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,4 +17,8 @@ class ProgramReminder(
|
||||||
or ((atInterval and 0x3f).toInt())
|
or ((atInterval and 0x3f).toInt())
|
||||||
).toByte()
|
).toByte()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ProgramReminder(atStart=$atStart, atEnd=$atEnd, atInterval=$atInterval)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ interface OmnipodDashPodStateManager {
|
||||||
|
|
||||||
val tempBasal: TempBasal?
|
val tempBasal: TempBasal?
|
||||||
val tempBasalActive: Boolean
|
val tempBasalActive: Boolean
|
||||||
val basalProgram: BasalProgram?
|
var basalProgram: BasalProgram?
|
||||||
|
|
||||||
fun increaseMessageSequenceNumber()
|
fun increaseMessageSequenceNumber()
|
||||||
fun increaseEapAkaSequenceNumber(): ByteArray
|
fun increaseEapAkaSequenceNumber(): ByteArray
|
||||||
|
|
|
@ -35,8 +35,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
override var activationProgress: ActivationProgress
|
override var activationProgress: ActivationProgress
|
||||||
get() = podState.activationProgress
|
get() = podState.activationProgress
|
||||||
set(value) {
|
set(activationProgress) {
|
||||||
podState.activationProgress = value
|
podState.activationProgress = activationProgress
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
override var lastConnection: Long
|
override var lastConnection: Long
|
||||||
get() = podState.lastConnection
|
get() = podState.lastConnection
|
||||||
set(value) {
|
set(lastConnection) {
|
||||||
podState.lastConnection = value
|
podState.lastConnection = lastConnection
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,8 +145,12 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
override val tempBasalActive: Boolean
|
override val tempBasalActive: Boolean
|
||||||
get() = tempBasal != null && tempBasal!!.startTime + tempBasal!!.durationInMinutes * 60 * 1000 > System.currentTimeMillis()
|
get() = tempBasal != null && tempBasal!!.startTime + tempBasal!!.durationInMinutes * 60 * 1000 > System.currentTimeMillis()
|
||||||
|
|
||||||
override val basalProgram: BasalProgram?
|
override var basalProgram: BasalProgram?
|
||||||
get() = podState.basalProgram
|
get() = podState.basalProgram
|
||||||
|
set(basalProgram) {
|
||||||
|
podState.basalProgram = basalProgram
|
||||||
|
store()
|
||||||
|
}
|
||||||
|
|
||||||
override fun increaseMessageSequenceNumber() {
|
override fun increaseMessageSequenceNumber() {
|
||||||
podState.messageSequenceNumber = ((podState.messageSequenceNumber.toInt() + 1) and 0x0f).toShort()
|
podState.messageSequenceNumber = ((podState.messageSequenceNumber.toInt() + 1) and 0x0f).toShort()
|
||||||
|
@ -155,15 +159,15 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
override var eapAkaSequenceNumber: Long
|
override var eapAkaSequenceNumber: Long
|
||||||
get() = podState.eapAkaSequenceNumber
|
get() = podState.eapAkaSequenceNumber
|
||||||
set(value) {
|
set(eapAkaSequenceNumber) {
|
||||||
podState.eapAkaSequenceNumber = value
|
podState.eapAkaSequenceNumber = eapAkaSequenceNumber
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
override var ltk: ByteArray?
|
override var ltk: ByteArray?
|
||||||
get() = podState.ltk
|
get() = podState.ltk
|
||||||
set(value) {
|
set(ltk) {
|
||||||
podState.ltk = value
|
podState.ltk = ltk
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +187,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
podState.deliveryStatus = response.deliveryStatus
|
podState.deliveryStatus = response.deliveryStatus
|
||||||
podState.podStatus = response.podStatus
|
podState.podStatus = response.podStatus
|
||||||
podState.pulsesDelivered = response.totalPulsesDelivered
|
podState.pulsesDelivered = response.totalPulsesDelivered
|
||||||
podState.pulsesRemaining = response.reservoirPulsesRemaining
|
if (response.reservoirPulsesRemaining < 1023) {
|
||||||
|
podState.pulsesRemaining = response.reservoirPulsesRemaining
|
||||||
|
}
|
||||||
podState.sequenceNumberOfLastProgrammingCommand = response.sequenceNumberOfLastProgrammingCommand
|
podState.sequenceNumberOfLastProgrammingCommand = response.sequenceNumberOfLastProgrammingCommand
|
||||||
podState.minutesSinceActivation = response.minutesSinceActivation
|
podState.minutesSinceActivation = response.minutesSinceActivation
|
||||||
podState.activeAlerts = response.activeAlerts
|
podState.activeAlerts = response.activeAlerts
|
||||||
|
@ -216,8 +222,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
override fun updateFromSetUniqueIdResponse(response: SetUniqueIdResponse) {
|
override fun updateFromSetUniqueIdResponse(response: SetUniqueIdResponse) {
|
||||||
podState.pulseRate = response.pumpRate
|
podState.pulseRate = response.pumpRate
|
||||||
podState.primePulseRate = response.primePumpRate
|
podState.primePulseRate = response.primePumpRate
|
||||||
podState.firstPrimeBolusVolume = response.numberOfPrimePulses
|
podState.firstPrimeBolusVolume = response.numberOfEngagingClutchDrivePulses
|
||||||
podState.secondPrimeBolusVolume = response.numberOfEngagingClutchDrivePulses
|
podState.secondPrimeBolusVolume = response.numberOfPrimePulses
|
||||||
podState.podLifeInHours = response.podExpirationTimeInHours
|
podState.podLifeInHours = response.podExpirationTimeInHours
|
||||||
podState.bleVersion = SoftwareVersion(
|
podState.bleVersion = SoftwareVersion(
|
||||||
response.bleVersionMajor,
|
response.bleVersionMajor,
|
||||||
|
|
|
@ -20,14 +20,12 @@ import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.queue.events.EventQueueChanged
|
import info.nightscout.androidaps.queue.events.EventQueueChanged
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
|
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by andy on 30/08/2019
|
|
||||||
*/
|
|
||||||
class DashPodManagementActivity : NoSplashAppCompatActivity() {
|
class DashPodManagementActivity : NoSplashAppCompatActivity() {
|
||||||
|
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@ -70,13 +68,12 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() {
|
||||||
this,
|
this,
|
||||||
resourceHelper.gs(R.string.omnipod_common_pod_management_discard_pod_confirmation),
|
resourceHelper.gs(R.string.omnipod_common_pod_management_discard_pod_confirmation),
|
||||||
Thread {
|
Thread {
|
||||||
// TODO discard Pod
|
podStateManager.reset()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.buttonPlayTestBeep.setOnClickListener {
|
binding.buttonPlayTestBeep.setOnClickListener {
|
||||||
// TODO
|
|
||||||
binding.buttonPlayTestBeep.isEnabled = false
|
binding.buttonPlayTestBeep.isEnabled = false
|
||||||
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_playing_test_beep)
|
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_playing_test_beep)
|
||||||
|
|
||||||
|
@ -117,7 +114,33 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshButtons() {
|
private fun refreshButtons() {
|
||||||
// TODO update button state from Pod state
|
// Only show the discard button to reset a cached unique ID before the unique ID has actually been set
|
||||||
|
// Otherwise, users should use the Deactivate Pod Wizard. In case proper deactivation fails,
|
||||||
|
// they will get an option to discard the Pod there
|
||||||
|
val discardButtonEnabled =
|
||||||
|
podStateManager.uniqueId != null && podStateManager.activationProgress.isBefore(ActivationProgress.SET_UNIQUE_ID)
|
||||||
|
binding.buttonDiscardPod.visibility = discardButtonEnabled.toVisibility()
|
||||||
|
|
||||||
|
binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)
|
||||||
|
binding.buttonDeactivatePod.isEnabled =
|
||||||
|
podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)
|
||||||
|
|
||||||
|
if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)) {
|
||||||
|
if (commandQueue.isCustomCommandInQueue(CommandPlayTestBeep::class.java)) {
|
||||||
|
binding.buttonPlayTestBeep.isEnabled = false
|
||||||
|
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_playing_test_beep)
|
||||||
|
} else {
|
||||||
|
binding.buttonPlayTestBeep.isEnabled = true
|
||||||
|
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_play_test_beep)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.buttonPlayTestBeep.isEnabled = false
|
||||||
|
binding.buttonPlayTestBeep.setText(R.string.omnipod_common_pod_management_button_play_test_beep)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (discardButtonEnabled) {
|
||||||
|
binding.buttonDiscardPod.isEnabled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun displayErrorDialog(title: String, message: String, @Suppress("SameParameterValue") withSound: Boolean) {
|
private fun displayErrorDialog(title: String, message: String, @Suppress("SameParameterValue") withSound: Boolean) {
|
||||||
|
|
|
@ -18,9 +18,9 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewButtonsBinding
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewButtonsBinding
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewPodInfoBinding
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewPodInfoBinding
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandAcknowledgeAlerts
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.EventOmnipodDashPumpValuesChanged
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.EventOmnipodDashPumpValuesChanged
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
|
||||||
|
@ -130,7 +130,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
buttonBinding.buttonSilenceAlerts.setOnClickListener {
|
buttonBinding.buttonSilenceAlerts.setOnClickListener {
|
||||||
disablePodActionButtons()
|
disablePodActionButtons()
|
||||||
commandQueue.customCommand(
|
commandQueue.customCommand(
|
||||||
CommandAcknowledgeAlerts(),
|
CommandSilenceAlerts(),
|
||||||
DisplayResultDialogCallback(
|
DisplayResultDialogCallback(
|
||||||
resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts),
|
resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts),
|
||||||
false
|
false
|
||||||
|
@ -295,7 +295,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
// total delivered
|
// total delivered
|
||||||
podInfoBinding.totalDelivered.text =
|
podInfoBinding.totalDelivered.text =
|
||||||
if (podStateManager.isActivationCompleted && podStateManager.pulsesDelivered != null) {
|
if (podStateManager.isActivationCompleted && podStateManager.pulsesDelivered != null) {
|
||||||
resourceHelper.gs(R.string.omnipod_common_overview_total_delivered_value, podStateManager.pulseRate)
|
resourceHelper.gs(
|
||||||
|
R.string.omnipod_common_overview_total_delivered_value,
|
||||||
|
podStateManager.pulsesDelivered!! * 0.05
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
PLACEHOLDER
|
PLACEHOLDER
|
||||||
}
|
}
|
||||||
|
@ -313,7 +316,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
|
|
||||||
podInfoBinding.reservoir.text = resourceHelper.gs(
|
podInfoBinding.reservoir.text = resourceHelper.gs(
|
||||||
R.string.omnipod_common_overview_reservoir_value,
|
R.string.omnipod_common_overview_reservoir_value,
|
||||||
podStateManager.pulsesRemaining
|
(podStateManager.pulsesRemaining!! * 0.05)
|
||||||
)
|
)
|
||||||
podInfoBinding.reservoir.setTextColor(
|
podInfoBinding.reservoir.setTextColor(
|
||||||
if (podStateManager.pulsesRemaining!! < lowReservoirThreshold) {
|
if (podStateManager.pulsesRemaining!! < lowReservoirThreshold) {
|
||||||
|
@ -465,8 +468,8 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
private fun updateRefreshStatusButton() {
|
private fun updateRefreshStatusButton() {
|
||||||
buttonBinding.buttonRefreshStatus.isEnabled =
|
buttonBinding.buttonRefreshStatus.isEnabled =
|
||||||
podStateManager.isUniqueIdSet &&
|
podStateManager.isUniqueIdSet &&
|
||||||
podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) &&
|
podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) &&
|
||||||
isQueueEmpty()
|
isQueueEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateResumeDeliveryButton() {
|
private fun updateResumeDeliveryButton() {
|
||||||
|
@ -484,7 +487,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
if (isAutomaticallySilenceAlertsEnabled() && podStateManager.isPodRunning &&
|
if (isAutomaticallySilenceAlertsEnabled() && podStateManager.isPodRunning &&
|
||||||
(
|
(
|
||||||
podStateManager.activeAlerts!!.size > 0 ||
|
podStateManager.activeAlerts!!.size > 0 ||
|
||||||
commandQueue.isCustomCommandInQueue(CommandAcknowledgeAlerts::class.java)
|
commandQueue.isCustomCommandInQueue(CommandSilenceAlerts::class.java)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE
|
buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE
|
||||||
|
|
|
@ -32,7 +32,14 @@ class DashInsertCannulaViewModel @Inject constructor(
|
||||||
if (profile == null) {
|
if (profile == null) {
|
||||||
source.onError(IllegalStateException("No profile set"))
|
source.onError(IllegalStateException("No profile set"))
|
||||||
} else {
|
} else {
|
||||||
val disposable = omnipodManager.activatePodPart2(mapProfileToBasalProgram(profile)).subscribeBy(
|
val basalProgram = mapProfileToBasalProgram(profile)
|
||||||
|
logger.debug(
|
||||||
|
LTag.PUMPCOMM,
|
||||||
|
"Mapped profile to basal program. profile={}, basalProgram={}",
|
||||||
|
profile,
|
||||||
|
basalProgram
|
||||||
|
)
|
||||||
|
val disposable = omnipodManager.activatePodPart2(basalProgram).subscribeBy(
|
||||||
onNext = { podEvent ->
|
onNext = { podEvent ->
|
||||||
logger.debug(
|
logger.debug(
|
||||||
LTag.PUMP,
|
LTag.PUMP,
|
||||||
|
|
|
@ -3,25 +3,33 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.deactivat
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult
|
import info.nightscout.androidaps.data.PumpEnactResult
|
||||||
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.R
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.R
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandDeactivatePod
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.deactivation.viewmodel.action.DeactivatePodViewModel
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.deactivation.viewmodel.action.DeactivatePodViewModel
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||||
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class DashDeactivatePodViewModel @Inject constructor(
|
class DashDeactivatePodViewModel @Inject constructor(
|
||||||
private val omnipodManager: OmnipodDashManager,
|
private val podStateManager: OmnipodDashPodStateManager,
|
||||||
|
private val commandQueueProvider: CommandQueueProvider,
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
logger: AAPSLogger
|
logger: AAPSLogger
|
||||||
) : DeactivatePodViewModel(injector, logger) {
|
) : DeactivatePodViewModel(injector, logger) {
|
||||||
|
|
||||||
override fun doExecuteAction(): Single<PumpEnactResult> = Single.just(
|
override fun doExecuteAction(): Single<PumpEnactResult> = Single.create { source ->
|
||||||
PumpEnactResult(injector).success(true).comment("TODO")
|
commandQueueProvider.customCommand(CommandDeactivatePod(), object : Callback() {
|
||||||
) // TODO
|
override fun run() {
|
||||||
|
source.onSuccess(result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
override fun discardPod() {
|
override fun discardPod() {
|
||||||
// TODO
|
podStateManager.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
|
|
|
@ -41,7 +41,7 @@ fun mapProfileToBasalProgram(profile: Profile): BasalProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entries.size == 0 && basalValue.timeAsSeconds != 0) {
|
if (entries.size == 0 && basalValue.timeAsSeconds != 0) {
|
||||||
throw java.lang.IllegalArgumentException("First basal segment start time should be 0")
|
throw IllegalArgumentException("First basal segment start time should be 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entries.size > 0 && entries[entries.size - 1].endSlotIndex != startSlotIndex) {
|
if (entries.size > 0 && entries[entries.size - 1].endSlotIndex != startSlotIndex) {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/omnipod_eros_pod_management_title"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="10dp"
|
android:layout_marginLeft="10dp"
|
||||||
|
@ -119,7 +118,7 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintGuide_percent="0.5" />
|
app:layout_constraintGuide_percent="0.5" />
|
||||||
|
|
||||||
<info.nightscout.androidaps.utils.ui.SingleClickButton
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
android:id="@+id/button_discard_pod"
|
android:id="@+id/button_discard_pod"
|
||||||
style="?android:attr/buttonStyle"
|
style="?android:attr/buttonStyle"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
|
@ -4,7 +4,7 @@ import com.google.crypto.tink.subtle.Hex
|
||||||
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||||
import info.nightscout.androidaps.utils.extensions.toHex
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class MessagePacketTest {
|
class MessagePacketTest {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import org.junit.Test
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PayloadSplitJoinTest {
|
class PayloadSplitJoinTest {
|
||||||
|
|
||||||
private val random = Random(42)
|
private val random = Random(42)
|
||||||
|
|
||||||
@Test fun testSplitAndJoinBack() {
|
@Test fun testSplitAndJoinBack() {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import org.junit.Assert.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class PayloadSplitterTest {
|
class PayloadSplitterTest {
|
||||||
|
|
||||||
@Test fun testSplitter() {
|
@Test fun testSplitter() {
|
||||||
val f1 = "00,01,54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30".replace(",", "")
|
val f1 = "00,01,54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30".replace(",", "")
|
||||||
val f2 = "01,04,bc,20,1f,f6,3d,00,01,a5,ff,ff,ff,fe,08,20,2e,a8,50,30".replace(",", "")
|
val f2 = "01,04,bc,20,1f,f6,3d,00,01,a5,ff,ff,ff,fe,08,20,2e,a8,50,30".replace(",", "")
|
||||||
|
|
|
@ -2,10 +2,11 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
import com.google.crypto.tink.subtle.Hex
|
import com.google.crypto.tink.subtle.Hex
|
||||||
import info.nightscout.androidaps.utils.extensions.toHex
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class StringLengthPrefixEncodingTest {
|
class StringLengthPrefixEncodingTest {
|
||||||
|
|
||||||
private val p0Payload = Hex.decode("50,30,3d,00,01,a5".replace(",", "")) // from logs
|
private val p0Payload = Hex.decode("50,30,3d,00,01,a5".replace(",", "")) // from logs
|
||||||
private val p0Content = Hex.decode("a5")
|
private val p0Content = Hex.decode("a5")
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
||||||
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
||||||
import info.nightscout.androidaps.utils.extensions.toHex
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Assert.*
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.spongycastle.util.encoders.Hex
|
import org.spongycastle.util.encoders.Hex
|
||||||
|
|
||||||
|
@ -11,7 +10,8 @@ class EapMessageTest {
|
||||||
|
|
||||||
@Test fun testParseAndBack() {
|
@Test fun testParseAndBack() {
|
||||||
val aapsLogger = AAPSLoggerTest()
|
val aapsLogger = AAPSLoggerTest()
|
||||||
val payload = Hex.decode("01bd0038170100000205000000c55c78e8d3b9b9e935860a7259f6c001050000c2cd1248451103bd77a6c7ef88c441ba7e0200006cff5d18")
|
val payload =
|
||||||
|
Hex.decode("01bd0038170100000205000000c55c78e8d3b9b9e935860a7259f6c001050000c2cd1248451103bd77a6c7ef88c441ba7e0200006cff5d18")
|
||||||
val eapMsg = EapMessage.parse(aapsLogger, payload)
|
val eapMsg = EapMessage.parse(aapsLogger, payload)
|
||||||
val back = eapMsg.toByteArray()
|
val back = eapMsg.toByteArray()
|
||||||
Assert.assertEquals(back.toHex(), payload.toHex())
|
Assert.assertEquals(back.toHex(), payload.toHex())
|
||||||
|
|
|
@ -8,11 +8,11 @@ import org.junit.Test
|
||||||
class DeactivateCommandTest {
|
class DeactivateCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testEncoding() {
|
@Test @Throws(DecoderException::class) fun testEncoding() {
|
||||||
val encoded = DeactivateCommand.Builder() //
|
val encoded = DeactivateCommand.Builder()
|
||||||
.setUniqueId(37879809) //
|
.setUniqueId(37879809)
|
||||||
.setSequenceNumber(5.toShort()) //
|
.setSequenceNumber(5.toShort())
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("0242000114061C04494E532E001C"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("0242000114061C04494E532E001C"), encoded)
|
||||||
|
|
|
@ -9,11 +9,11 @@ import org.junit.Test
|
||||||
class GetStatusCommandTest {
|
class GetStatusCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testGetDefaultStatusResponse() {
|
@Test @Throws(DecoderException::class) fun testGetDefaultStatusResponse() {
|
||||||
val encoded = GetStatusCommand.Builder() //
|
val encoded = GetStatusCommand.Builder()
|
||||||
.setUniqueId(37879810) //
|
.setUniqueId(37879810)
|
||||||
.setSequenceNumber(15.toShort()) //
|
.setSequenceNumber(15.toShort())
|
||||||
.setStatusResponseType(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE) //
|
.setStatusResponseType(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("024200023C030E0100024C"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("024200023C030E0100024C"), encoded)
|
||||||
|
|
|
@ -8,10 +8,10 @@ import org.junit.Test
|
||||||
class GetVersionCommandTest {
|
class GetVersionCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testEncoding() {
|
@Test @Throws(DecoderException::class) fun testEncoding() {
|
||||||
val encoded = GetVersionCommand.Builder() //
|
val encoded = GetVersionCommand.Builder()
|
||||||
.setSequenceNumber(0.toShort()) //
|
.setSequenceNumber(0.toShort())
|
||||||
.setUniqueId(GetVersionCommand.DEFAULT_UNIQUE_ID) //
|
.setUniqueId(GetVersionCommand.DEFAULT_UNIQUE_ID)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("FFFFFFFF00060704FFFFFFFF82B2"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("FFFFFFFF00060704FFFFFFFF82B2"), encoded)
|
||||||
|
|
|
@ -15,16 +15,36 @@ class ProgramAlertsCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testExpirationAlerts() {
|
@Test @Throws(DecoderException::class) fun testExpirationAlerts() {
|
||||||
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
||||||
configurations.add(AlertConfiguration(AlertType.EXPIRATION, true, 420.toShort(), false, AlertTrigger.TimerTrigger(4305.toShort()), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX3))
|
configurations.add(
|
||||||
configurations.add(AlertConfiguration(AlertType.EXPIRATION_IMMINENT, true, 0.toShort(), false, AlertTrigger.TimerTrigger(4725.toShort()), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX4))
|
AlertConfiguration(
|
||||||
|
AlertType.EXPIRATION,
|
||||||
|
true,
|
||||||
|
420.toShort(),
|
||||||
|
false,
|
||||||
|
AlertTrigger.TimerTrigger(4305.toShort()),
|
||||||
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
|
BeepRepetitionType.XXX3
|
||||||
|
)
|
||||||
|
)
|
||||||
|
configurations.add(
|
||||||
|
AlertConfiguration(
|
||||||
|
AlertType.EXPIRATION_IMMINENT,
|
||||||
|
true,
|
||||||
|
0.toShort(),
|
||||||
|
false,
|
||||||
|
AlertTrigger.TimerTrigger(4725.toShort()),
|
||||||
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
|
BeepRepetitionType.XXX4
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val encoded = ProgramAlertsCommand.Builder() //
|
val encoded = ProgramAlertsCommand.Builder()
|
||||||
.setUniqueId(37879811) //
|
.setUniqueId(37879811)
|
||||||
.setSequenceNumber(3.toShort()) //
|
.setSequenceNumber(3.toShort())
|
||||||
.setMultiCommandFlag(true) //
|
.setMultiCommandFlag(true)
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setAlertConfigurations(configurations) //
|
.setAlertConfigurations(configurations)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("024200038C121910494E532E79A410D1050228001275060280F5"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("024200038C121910494E532E79A410D1050228001275060280F5"), encoded)
|
||||||
|
@ -32,14 +52,24 @@ class ProgramAlertsCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testLowReservoirAlert() {
|
@Test @Throws(DecoderException::class) fun testLowReservoirAlert() {
|
||||||
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
||||||
configurations.add(AlertConfiguration(AlertType.LOW_RESERVOIR, true, 0.toShort(), false, AlertTrigger.ReservoirVolumeTrigger(200.toShort()), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX))
|
configurations.add(
|
||||||
|
AlertConfiguration(
|
||||||
|
AlertType.LOW_RESERVOIR,
|
||||||
|
true,
|
||||||
|
0.toShort(),
|
||||||
|
false,
|
||||||
|
AlertTrigger.ReservoirVolumeTrigger(200.toShort()),
|
||||||
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
|
BeepRepetitionType.XXX
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val encoded = ProgramAlertsCommand.Builder() //
|
val encoded = ProgramAlertsCommand.Builder()
|
||||||
.setUniqueId(37879811) //
|
.setUniqueId(37879811)
|
||||||
.setSequenceNumber(8.toShort()) //
|
.setSequenceNumber(8.toShort())
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setAlertConfigurations(configurations) //
|
.setAlertConfigurations(configurations)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("02420003200C190A494E532E4C0000C801020149"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("02420003200C190A494E532E4C0000C801020149"), encoded)
|
||||||
|
@ -47,14 +77,24 @@ class ProgramAlertsCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testUserExpirationAlert() {
|
@Test @Throws(DecoderException::class) fun testUserExpirationAlert() {
|
||||||
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
||||||
configurations.add(AlertConfiguration(AlertType.USER_SET_EXPIRATION, true, 0.toShort(), false, AlertTrigger.TimerTrigger(4079.toShort()), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX2))
|
configurations.add(
|
||||||
|
AlertConfiguration(
|
||||||
|
AlertType.USER_SET_EXPIRATION,
|
||||||
|
true,
|
||||||
|
0.toShort(),
|
||||||
|
false,
|
||||||
|
AlertTrigger.TimerTrigger(4079.toShort()),
|
||||||
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
|
BeepRepetitionType.XXX2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val encoded = ProgramAlertsCommand.Builder() //
|
val encoded = ProgramAlertsCommand.Builder()
|
||||||
.setUniqueId(37879811) //
|
.setUniqueId(37879811)
|
||||||
.setSequenceNumber(15.toShort()) //
|
.setSequenceNumber(15.toShort())
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setAlertConfigurations(configurations) //
|
.setAlertConfigurations(configurations)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("024200033C0C190A494E532E38000FEF030203E2"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("024200033C0C190A494E532E38000FEF030203E2"), encoded)
|
||||||
|
@ -62,15 +102,25 @@ class ProgramAlertsCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testLumpOfCoalAlert() {
|
@Test @Throws(DecoderException::class) fun testLumpOfCoalAlert() {
|
||||||
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
||||||
configurations.add(AlertConfiguration(AlertType.EXPIRATION, true, 55.toShort(), false, AlertTrigger.TimerTrigger(5.toShort()), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX5))
|
configurations.add(
|
||||||
|
AlertConfiguration(
|
||||||
|
AlertType.EXPIRATION,
|
||||||
|
true,
|
||||||
|
55.toShort(),
|
||||||
|
false,
|
||||||
|
AlertTrigger.TimerTrigger(5.toShort()),
|
||||||
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
|
BeepRepetitionType.XXX5
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val encoded = ProgramAlertsCommand.Builder() //
|
val encoded = ProgramAlertsCommand.Builder()
|
||||||
.setUniqueId(37879811) //
|
.setUniqueId(37879811)
|
||||||
.setSequenceNumber(10.toShort()) //
|
.setSequenceNumber(10.toShort())
|
||||||
.setMultiCommandFlag(false) //
|
.setMultiCommandFlag(false)
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setAlertConfigurations(configurations) //
|
.setAlertConfigurations(configurations)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("02420003280C190A494E532E7837000508020356"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("02420003280C190A494E532E7837000508020356"), encoded)
|
||||||
|
|
|
@ -15,18 +15,45 @@ class ProgramBasalCommandTest {
|
||||||
BasalProgram.Segment(0.toShort(), 48.toShort(), 300)
|
BasalProgram.Segment(0.toShort(), 48.toShort(), 300)
|
||||||
)
|
)
|
||||||
val basalProgram = BasalProgram(segments)
|
val basalProgram = BasalProgram(segments)
|
||||||
val date = Date(2021, 1, 17, 14, 47, 43)
|
val date = Date(121, 1, 17, 14, 47, 43)
|
||||||
|
|
||||||
val encoded = ProgramBasalCommand.Builder() //
|
val encoded = ProgramBasalCommand.Builder()
|
||||||
.setUniqueId(37879809) //
|
.setUniqueId(37879809)
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setSequenceNumber(10.toShort()) //
|
.setSequenceNumber(10.toShort())
|
||||||
.setBasalProgram(basalProgram) //
|
.setBasalProgram(basalProgram)
|
||||||
.setCurrentTime(date) //
|
.setCurrentTime(date)
|
||||||
.setProgramReminder(ProgramReminder(false, true, 0.toByte())) //
|
.setProgramReminder(ProgramReminder(false, true, 0.toByte()))
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("0242000128241A12494E532E0005E81D1708000CF01EF01EF01E130E40001593004C4B403840005B8D80827C"), encoded)
|
Assert.assertArrayEquals(
|
||||||
|
Hex.decodeHex("0242000128241A12494E532E0005E81D1708000CF01EF01EF01E130E40001593004C4B403840005B8D80827C"),
|
||||||
|
encoded
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test @Throws(DecoderException::class) fun testProgramBasalCommandWithExtraAlternateSegmentPulse() {
|
||||||
|
val segments = listOf(
|
||||||
|
BasalProgram.Segment(0.toShort(), 48.toShort(), 5)
|
||||||
|
)
|
||||||
|
val basalProgram = BasalProgram(segments)
|
||||||
|
val date = Date(121, 0, 30, 23, 21, 46)
|
||||||
|
|
||||||
|
val encoded = ProgramBasalCommand.Builder()
|
||||||
|
.setUniqueId(4241)
|
||||||
|
.setNonce(1229869870)
|
||||||
|
.setSequenceNumber(12.toShort())
|
||||||
|
.setBasalProgram(basalProgram)
|
||||||
|
.setCurrentTime(date)
|
||||||
|
.setProgramReminder(ProgramReminder(atStart = false, atEnd = false, atInterval = 0.toByte()))
|
||||||
|
.build()
|
||||||
|
.encoded
|
||||||
|
|
||||||
|
Assert.assertArrayEquals(
|
||||||
|
Hex.decodeHex("0000109130241a12494e532e0000c52e0f700000f800f800f800130e0000000707fcad8000f015752a00033b"),
|
||||||
|
encoded
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,14 @@ import org.junit.Test
|
||||||
class ProgramBeepsCommandTest {
|
class ProgramBeepsCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testPlayTestBeep() {
|
@Test @Throws(DecoderException::class) fun testPlayTestBeep() {
|
||||||
val encoded = ProgramBeepsCommand.Builder() //
|
val encoded = ProgramBeepsCommand.Builder()
|
||||||
.setUniqueId(37879810) //
|
.setUniqueId(37879810)
|
||||||
.setSequenceNumber(11.toShort()) //
|
.setSequenceNumber(11.toShort())
|
||||||
.setImmediateBeepType(BeepType.FOUR_TIMES_BIP_BEEP) //
|
.setImmediateBeepType(BeepType.FOUR_TIMES_BIP_BEEP)
|
||||||
.setBasalReminder(ProgramReminder(false, false, 0.toByte())) //
|
.setBasalReminder(ProgramReminder(false, false, 0.toByte()))
|
||||||
.setTempBasalReminder(ProgramReminder(false, false, 0.toByte())) //
|
.setTempBasalReminder(ProgramReminder(false, false, 0.toByte()))
|
||||||
.setBolusReminder(ProgramReminder(false, false, 0.toByte())) //
|
.setBolusReminder(ProgramReminder(false, false, 0.toByte()))
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("024200022C061E0402000000800F"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("024200022C061E0402000000800F"), encoded)
|
||||||
|
|
|
@ -9,16 +9,19 @@ import org.junit.Test
|
||||||
class ProgramBolusCommandTest {
|
class ProgramBolusCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testProgramBolusCommand() {
|
@Test @Throws(DecoderException::class) fun testProgramBolusCommand() {
|
||||||
val encoded = ProgramBolusCommand.Builder() //
|
val encoded = ProgramBolusCommand.Builder()
|
||||||
.setNumberOfUnits(5.0) //
|
.setNumberOfUnits(5.0)
|
||||||
.setProgramReminder(ProgramReminder(false, true, 0.toByte())) //
|
.setProgramReminder(ProgramReminder(false, true, 0.toByte()))
|
||||||
.setDelayBetweenPulsesInEighthSeconds(16.toByte()) //
|
.setDelayBetweenPulsesInEighthSeconds(16.toByte())
|
||||||
.setUniqueId(37879809) //
|
.setUniqueId(37879809)
|
||||||
.setSequenceNumber(14.toShort()) //
|
.setSequenceNumber(14.toShort())
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("02420001381F1A0E494E532E02010F01064000640064170D4003E800030D4000000000000080F6"), encoded)
|
Assert.assertArrayEquals(
|
||||||
|
Hex.decodeHex("02420001381F1A0E494E532E02010F01064000640064170D4003E800030D4000000000000080F6"),
|
||||||
|
encoded
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,28 +9,34 @@ import org.junit.Test
|
||||||
class ProgramTempBasalCommandTest {
|
class ProgramTempBasalCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testExtraAlternateSegmentPulseTempBasal() {
|
@Test @Throws(DecoderException::class) fun testExtraAlternateSegmentPulseTempBasal() {
|
||||||
val command = ProgramTempBasalCommand.Builder() //
|
val command = ProgramTempBasalCommand.Builder()
|
||||||
.setUniqueId(37879809) //
|
.setUniqueId(37879809)
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setSequenceNumber(15.toShort()) //
|
.setSequenceNumber(15.toShort())
|
||||||
.setRateInUnitsPerHour(5.05) //
|
.setRateInUnitsPerHour(5.05)
|
||||||
.setDurationInMinutes(60.toShort()) //
|
.setDurationInMinutes(60.toShort())
|
||||||
.setProgramReminder(ProgramReminder(false, true, 0.toByte())) //
|
.setProgramReminder(ProgramReminder(false, true, 0.toByte()))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("024200013C201A0E494E532E01011102384000321832160E400003F20036634403F20036634482A6"), command.encoded)
|
Assert.assertArrayEquals(
|
||||||
|
Hex.decodeHex("024200013C201A0E494E532E01011102384000321832160E400003F20036634403F20036634482A6"),
|
||||||
|
command.encoded
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testZeroTempBasal() {
|
@Test @Throws(DecoderException::class) fun testZeroTempBasal() {
|
||||||
val command = ProgramTempBasalCommand.Builder() //
|
val command = ProgramTempBasalCommand.Builder()
|
||||||
.setUniqueId(37879809) //
|
.setUniqueId(37879809)
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setSequenceNumber(7.toShort()) //
|
.setSequenceNumber(7.toShort())
|
||||||
.setRateInUnitsPerHour(0.0) //
|
.setRateInUnitsPerHour(0.0)
|
||||||
.setDurationInMinutes(300.toShort()) //
|
.setDurationInMinutes(300.toShort())
|
||||||
.setProgramReminder(ProgramReminder(true, true, 0.toByte())) //
|
.setProgramReminder(ProgramReminder(true, true, 0.toByte()))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("024200011C201A0E494E532E0100820A384000009000160EC000000A6B49D200000AEB49D20001DE"), command.encoded)
|
Assert.assertArrayEquals(
|
||||||
|
Hex.decodeHex("024200011C201A0E494E532E0100820A384000009000160EC000000A6B49D200000AEB49D20001DE"),
|
||||||
|
command.encoded
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,13 @@ import java.util.*
|
||||||
class SetUniqueIdCommandTest {
|
class SetUniqueIdCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testEncoding() {
|
@Test @Throws(DecoderException::class) fun testEncoding() {
|
||||||
val encoded = SetUniqueIdCommand.Builder() //
|
val encoded = SetUniqueIdCommand.Builder()
|
||||||
.setUniqueId(37879811) //
|
.setUniqueId(37879811)
|
||||||
.setSequenceNumber(6.toShort()) //
|
.setSequenceNumber(6.toShort())
|
||||||
.setLotNumber(135556289) //
|
.setLotNumber(135556289)
|
||||||
.setPodSequenceNumber(681767) //
|
.setPodSequenceNumber(681767)
|
||||||
.setInitializationTime(Date(2021, 1, 10, 14, 41)) //
|
.setInitializationTime(Date(2021, 1, 10, 14, 41))
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("FFFFFFFF18150313024200031404020A150E2908146CC1000A67278344"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("FFFFFFFF18150313024200031404020A150E2908146CC1000A67278344"), encoded)
|
||||||
|
|
|
@ -10,12 +10,12 @@ import java.util.*
|
||||||
class SilenceAlertsCommandTest {
|
class SilenceAlertsCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testSilenceLowReservoirAlert() {
|
@Test @Throws(DecoderException::class) fun testSilenceLowReservoirAlert() {
|
||||||
val encoded = SilenceAlertsCommand.Builder() //
|
val encoded = SilenceAlertsCommand.Builder()
|
||||||
.setUniqueId(37879811) //
|
.setUniqueId(37879811)
|
||||||
.setSequenceNumber(1.toShort()) //
|
.setSequenceNumber(1.toShort())
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setAlertTypes(EnumSet.of(AlertType.LOW_RESERVOIR)) //
|
.setAlertTypes(EnumSet.of(AlertType.LOW_RESERVOIR))
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("0242000304071105494E532E1081CE"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("0242000304071105494E532E1081CE"), encoded)
|
||||||
|
|
|
@ -9,26 +9,26 @@ import org.junit.Test
|
||||||
class StopDeliveryCommandTest {
|
class StopDeliveryCommandTest {
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testStopTempBasal() {
|
@Test @Throws(DecoderException::class) fun testStopTempBasal() {
|
||||||
val encoded = StopDeliveryCommand.Builder() //
|
val encoded = StopDeliveryCommand.Builder()
|
||||||
.setUniqueId(37879811) //
|
.setUniqueId(37879811)
|
||||||
.setSequenceNumber(0.toShort()) //
|
.setSequenceNumber(0.toShort())
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setDeliveryType(StopDeliveryCommand.DeliveryType.TEMP_BASAL) //
|
.setDeliveryType(StopDeliveryCommand.DeliveryType.TEMP_BASAL)
|
||||||
.setBeepType(BeepType.LONG_SINGLE_BEEP) //
|
.setBeepType(BeepType.LONG_SINGLE_BEEP)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("0242000300071F05494E532E6201B1"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("0242000300071F05494E532E6201B1"), encoded)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test @Throws(DecoderException::class) fun testSuspendDelivery() {
|
@Test @Throws(DecoderException::class) fun testSuspendDelivery() {
|
||||||
val encoded = StopDeliveryCommand.Builder() //
|
val encoded = StopDeliveryCommand.Builder()
|
||||||
.setUniqueId(37879811) //
|
.setUniqueId(37879811)
|
||||||
.setSequenceNumber(2.toShort()) //
|
.setSequenceNumber(2.toShort())
|
||||||
.setNonce(1229869870) //
|
.setNonce(1229869870)
|
||||||
.setDeliveryType(StopDeliveryCommand.DeliveryType.ALL) //
|
.setDeliveryType(StopDeliveryCommand.DeliveryType.ALL)
|
||||||
.setBeepType(BeepType.SILENT) //
|
.setBeepType(BeepType.SILENT)
|
||||||
.build() //
|
.build()
|
||||||
.encoded
|
.encoded
|
||||||
|
|
||||||
Assert.assertArrayEquals(Hex.decodeHex("0242000308071F05494E532E078287"), encoded)
|
Assert.assertArrayEquals(Hex.decodeHex("0242000308071F05494E532E078287"), encoded)
|
||||||
|
|
|
@ -65,7 +65,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLin
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData;
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData;
|
||||||
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
|
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType;
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandAcknowledgeAlerts;
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandDeactivatePod;
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandDeactivatePod;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange;
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandPlayTestBeep;
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandPlayTestBeep;
|
||||||
|
@ -253,7 +253,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && podStateManager.isPodActivationCompleted() && !podStateManager.isPodDead() &&
|
if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && podStateManager.isPodActivationCompleted() && !podStateManager.isPodDead() &&
|
||||||
podStateManager.getActiveAlerts().size() > 0 && !getCommandQueue().isCustomCommandInQueue(CommandAcknowledgeAlerts.class)) {
|
podStateManager.getActiveAlerts().size() > 0 && !getCommandQueue().isCustomCommandInQueue(CommandSilenceAlerts.class)) {
|
||||||
queueAcknowledgeAlertsCommand();
|
queueAcknowledgeAlertsCommand();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -410,7 +410,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa
|
||||||
rxBus.send(new EventNewNotification(notification));
|
rxBus.send(new EventNewNotification(notification));
|
||||||
nsUpload.uploadError(notificationText);
|
nsUpload.uploadError(notificationText);
|
||||||
|
|
||||||
if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && !getCommandQueue().isCustomCommandInQueue(CommandAcknowledgeAlerts.class)) {
|
if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && !getCommandQueue().isCustomCommandInQueue(CommandSilenceAlerts.class)) {
|
||||||
queueAcknowledgeAlertsCommand();
|
queueAcknowledgeAlertsCommand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,7 +437,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa
|
||||||
}
|
}
|
||||||
|
|
||||||
private void queueAcknowledgeAlertsCommand() {
|
private void queueAcknowledgeAlertsCommand() {
|
||||||
getCommandQueue().customCommand(new CommandAcknowledgeAlerts(), new Callback() {
|
getCommandQueue().customCommand(new CommandSilenceAlerts(), new Callback() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
aapsLogger.debug(LTag.PUMP, "Acknowledge alerts result: {} ({})", result.success, result.comment);
|
aapsLogger.debug(LTag.PUMP, "Acknowledge alerts result: {} ({})", result.success, result.comment);
|
||||||
|
@ -827,7 +827,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PumpEnactResult executeCustomCommand(@NonNull CustomCommand command) {
|
public PumpEnactResult executeCustomCommand(@NonNull CustomCommand command) {
|
||||||
if (command instanceof CommandAcknowledgeAlerts) {
|
if (command instanceof CommandSilenceAlerts) {
|
||||||
return executeCommand(OmnipodCommandType.ACKNOWLEDGE_ALERTS, aapsOmnipodErosManager::acknowledgeAlerts);
|
return executeCommand(OmnipodCommandType.ACKNOWLEDGE_ALERTS, aapsOmnipodErosManager::acknowledgeAlerts);
|
||||||
}
|
}
|
||||||
if (command instanceof CommandGetPodStatus) {
|
if (command instanceof CommandGetPodStatus) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLin
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewButtonsBinding
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewButtonsBinding
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewPodInfoBinding
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.databinding.OmnipodCommonOverviewPodInfoBinding
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandAcknowledgeAlerts
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandHandleTimeChange
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery
|
||||||
|
@ -148,7 +148,8 @@ class OmnipodErosOverviewFragment : DaggerFragment() {
|
||||||
|
|
||||||
buttonBinding.buttonSilenceAlerts.setOnClickListener {
|
buttonBinding.buttonSilenceAlerts.setOnClickListener {
|
||||||
disablePodActionButtons()
|
disablePodActionButtons()
|
||||||
commandQueue.customCommand(CommandAcknowledgeAlerts(),
|
commandQueue.customCommand(
|
||||||
|
CommandSilenceAlerts(),
|
||||||
DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts), false)
|
DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts), false)
|
||||||
.messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_silenced_alerts))
|
.messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_silenced_alerts))
|
||||||
.actionOnSuccess { rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_ALERTS)) })
|
.actionOnSuccess { rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_ALERTS)) })
|
||||||
|
@ -513,7 +514,8 @@ class OmnipodErosOverviewFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSilenceAlertsButton() {
|
private fun updateSilenceAlertsButton() {
|
||||||
if (!omnipodManager.isAutomaticallyAcknowledgeAlertsEnabled && podStateManager.isPodRunning && (podStateManager.hasActiveAlerts() || commandQueue.isCustomCommandInQueue(CommandAcknowledgeAlerts::class.java))) {
|
if (!omnipodManager.isAutomaticallyAcknowledgeAlertsEnabled && podStateManager.isPodRunning && (podStateManager.hasActiveAlerts() || commandQueue.isCustomCommandInQueue(
|
||||||
|
CommandSilenceAlerts::class.java))) {
|
||||||
buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE
|
buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE
|
||||||
buttonBinding.buttonSilenceAlerts.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty()
|
buttonBinding.buttonSilenceAlerts.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/omnipod_eros_pod_management_title"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="10dp"
|
android:layout_marginLeft="10dp"
|
||||||
|
@ -125,7 +124,7 @@
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintGuide_percent="0" />
|
app:layout_constraintGuide_percent="0" />
|
||||||
|
|
||||||
<info.nightscout.androidaps.utils.ui.SingleClickButton
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
android:id="@+id/button_play_test_beep"
|
android:id="@+id/button_play_test_beep"
|
||||||
style="?android:attr/buttonStyle"
|
style="?android:attr/buttonStyle"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -256,7 +255,7 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintGuide_percent="0.5" />
|
app:layout_constraintGuide_percent="0.5" />
|
||||||
|
|
||||||
<info.nightscout.androidaps.utils.ui.SingleClickButton
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
android:id="@+id/button_pulse_log"
|
android:id="@+id/button_pulse_log"
|
||||||
style="?android:attr/buttonStyle"
|
style="?android:attr/buttonStyle"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
Loading…
Reference in a new issue