From 18be54f48997f503a7b68c59efbc3341f6b971b0 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 18 Feb 2023 19:46:35 +0100
Subject: [PATCH 001/116] Empty plugin
---
app/build.gradle | 1 +
.../activities/MyPreferenceFragment.kt | 3 +
.../nightscout/androidaps/di/AppComponent.kt | 2 +
.../androidaps/di/PluginsListModule.kt | 7 +
.../interfaces/pump/defs/ManufacturerType.kt | 1 +
pump/medtrum/.gitignore | 1 +
pump/medtrum/build.gradle | 27 ++
pump/medtrum/consumer-rules.pro | 0
pump/medtrum/proguard-rules.pro | 21 ++
pump/medtrum/src/main/AndroidManifest.xml | 3 +
.../pump/medtrum/MedtrumPumpPlugin.kt | 219 +++++++++++++
.../pump/medtrum/di/MedtrumPumpModule.kt | 14 +
.../events/EventMedtrumPumpUpdateGui.kt | 5 +
.../pump/medtrum/ui/MedtrumPumpFragment.kt | 103 ++++++
.../main/res/layout/medtrum_pump_fragment.xml | 306 ++++++++++++++++++
pump/medtrum/src/main/res/values/strings.xml | 17 +
.../src/main/res/xml/pref_medtrum_pump.xml | 17 +
.../info/nightscout/androidaps/TestBase.kt | 37 +++
settings.gradle | 1 +
19 files changed, 785 insertions(+)
create mode 100644 pump/medtrum/.gitignore
create mode 100644 pump/medtrum/build.gradle
create mode 100644 pump/medtrum/consumer-rules.pro
create mode 100644 pump/medtrum/proguard-rules.pro
create mode 100644 pump/medtrum/src/main/AndroidManifest.xml
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/events/EventMedtrumPumpUpdateGui.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt
create mode 100644 pump/medtrum/src/main/res/layout/medtrum_pump_fragment.xml
create mode 100644 pump/medtrum/src/main/res/values/strings.xml
create mode 100644 pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
create mode 100644 pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
diff --git a/app/build.gradle b/app/build.gradle
index 19d1aab3a1..16c2b9c158 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -214,6 +214,7 @@ dependencies {
implementation project(':pump:danar')
implementation project(':pump:diaconn')
implementation project(':pump:eopatch')
+ implementation project(':pump:medtrum')
implementation project(':insight')
implementation project(':pump:medtronic')
implementation project(':pump:pump-common')
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
index 50a4030a9b..0fcd7aa767 100644
--- a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
@@ -54,6 +54,7 @@ import info.nightscout.plugins.sync.xdrip.XdripPlugin
import info.nightscout.pump.combo.ComboPlugin
import info.nightscout.pump.combov2.ComboV2Plugin
import info.nightscout.pump.diaconn.DiaconnG8Plugin
+import info.nightscout.pump.medtrum.MedtrumPumpPlugin
import info.nightscout.pump.virtual.VirtualPumpPlugin
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventPreferenceChange
@@ -122,6 +123,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
@Inject lateinit var wearPlugin: WearPlugin
@Inject lateinit var maintenancePlugin: MaintenancePlugin
@Inject lateinit var eopatchPumpPlugin: EopatchPumpPlugin
+ @Inject lateinit var medtrumPumpPlugin: MedtrumPumpPlugin
@Inject lateinit var passwordCheck: PasswordCheck
@Inject lateinit var nsSettingStatus: NSSettingsStatus
@@ -212,6 +214,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(diaconnG8Plugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(eopatchPumpPlugin, rootKey, config.PUMPDRIVERS)
+ addPreferencesFromResourceIfEnabled(medtrumPumpPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
diff --git a/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt b/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt
index def98a723c..4afc89af2d 100644
--- a/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt
+++ b/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt
@@ -33,6 +33,7 @@ import info.nightscout.pump.dana.di.DanaModule
import info.nightscout.pump.danars.di.DanaRSModule
import info.nightscout.pump.diaconn.di.DiaconnG8Module
import info.nightscout.pump.virtual.di.VirtualPumpModule
+import info.nightscout.pump.medtrum.di.MedtrumPumpModule
import info.nightscout.rx.di.RxModule
import info.nightscout.shared.di.SharedModule
import info.nightscout.shared.impl.di.SharedImplModule
@@ -87,6 +88,7 @@ import javax.inject.Singleton
OmnipodErosModule::class,
PumpCommonModule::class,
RileyLinkModule::class,
+ MedtrumPumpModule::class,
VirtualPumpModule::class
]
)
diff --git a/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt b/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt
index b30a77bf89..9dd3ea48b1 100644
--- a/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt
+++ b/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt
@@ -46,6 +46,7 @@ import info.nightscout.plugins.sync.tidepool.TidepoolPlugin
import info.nightscout.plugins.sync.xdrip.XdripPlugin
import info.nightscout.pump.combo.ComboPlugin
import info.nightscout.pump.combov2.ComboV2Plugin
+import info.nightscout.pump.medtrum.MedtrumPumpPlugin
import info.nightscout.pump.diaconn.DiaconnG8Plugin
import info.nightscout.pump.virtual.VirtualPumpPlugin
import info.nightscout.sensitivity.SensitivityAAPSPlugin
@@ -209,6 +210,12 @@ abstract class PluginsListModule {
@IntKey(156)
abstract fun bindEopatchPumpPlugin(plugin: EopatchPumpPlugin): PluginBase
+ @Binds
+ @PumpDriver
+ @IntoMap
+ @IntKey(160)
+ abstract fun bindMedtrumPumpPlugin(plugin: MedtrumPumpPlugin): PluginBase
+
@Binds
@AllConfigs
@IntoMap
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/ManufacturerType.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/ManufacturerType.kt
index ddecad988c..8ffcfeb6c6 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/ManufacturerType.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/ManufacturerType.kt
@@ -2,6 +2,7 @@ package info.nightscout.interfaces.pump.defs
enum class ManufacturerType(val description: String) {
AAPS("AAPS"),
+ Medtrum("Medtrum"),
Medtronic("Medtronic"),
Sooil("SOOIL"),
Tandem("Tandem"),
diff --git a/pump/medtrum/.gitignore b/pump/medtrum/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/pump/medtrum/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/pump/medtrum/build.gradle b/pump/medtrum/build.gradle
new file mode 100644
index 0000000000..39d231800f
--- /dev/null
+++ b/pump/medtrum/build.gradle
@@ -0,0 +1,27 @@
+plugins {
+ id 'com.android.library'
+ id 'kotlin-android'
+ id 'kotlin-kapt'
+ id 'kotlin-allopen'
+ id 'com.hiya.jacoco-android'
+}
+
+apply from: "${project.rootDir}/core/main/android_dependencies.gradle"
+apply from: "${project.rootDir}/core/main/android_module_dependencies.gradle"
+apply from: "${project.rootDir}/core/main/allopen_dependencies.gradle"
+apply from: "${project.rootDir}/core/main/test_dependencies.gradle"
+apply from: "${project.rootDir}/core/main/jacoco_global.gradle"
+
+android {
+
+ namespace 'info.nightscout.pump.medtrum'
+}
+
+dependencies {
+ implementation project(':app-wear-shared:shared')
+ implementation project(':database:entities')
+ implementation project(':core:interfaces')
+ implementation project(':core:main')
+ implementation project(':core:ui')
+ implementation project(':core:utils')
+}
\ No newline at end of file
diff --git a/pump/medtrum/consumer-rules.pro b/pump/medtrum/consumer-rules.pro
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/pump/medtrum/proguard-rules.pro b/pump/medtrum/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/pump/medtrum/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/pump/medtrum/src/main/AndroidManifest.xml b/pump/medtrum/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..0a0938ae37
--- /dev/null
+++ b/pump/medtrum/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
new file mode 100644
index 0000000000..1d2e4c0742
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
@@ -0,0 +1,219 @@
+package info.nightscout.pump.medtrum
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.interfaces.plugin.PluginDescription
+import info.nightscout.interfaces.plugin.PluginType
+import info.nightscout.interfaces.profile.Profile
+import info.nightscout.interfaces.profile.ProfileFunction
+import info.nightscout.interfaces.pump.DetailedBolusInfo
+import info.nightscout.interfaces.pump.Pump
+import info.nightscout.interfaces.pump.PumpEnactResult
+import info.nightscout.interfaces.pump.PumpPluginBase
+import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.pump.actions.CustomAction
+import info.nightscout.interfaces.pump.actions.CustomActionType
+import info.nightscout.interfaces.pump.defs.ManufacturerType
+import info.nightscout.interfaces.pump.defs.PumpDescription
+import info.nightscout.interfaces.pump.defs.PumpType
+import info.nightscout.interfaces.queue.CommandQueue
+import info.nightscout.interfaces.queue.CustomCommand
+import info.nightscout.interfaces.ui.UiInteraction
+import info.nightscout.interfaces.utils.TimeChangeType
+import info.nightscout.pump.medtrum.ui.MedtrumPumpFragment
+import info.nightscout.rx.AapsSchedulers
+import info.nightscout.rx.bus.RxBus
+import info.nightscout.rx.events.EventAppInitialized
+import info.nightscout.rx.events.EventOverviewBolusProgress
+import info.nightscout.rx.events.EventPreferenceChange
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.interfaces.ResourceHelper
+import info.nightscout.shared.utils.DateUtil
+import info.nightscout.shared.utils.T
+import io.reactivex.rxjava3.disposables.CompositeDisposable
+import io.reactivex.rxjava3.functions.Consumer
+import io.reactivex.rxjava3.subjects.BehaviorSubject
+import org.json.JSONException
+import org.json.JSONObject
+import javax.inject.Inject
+import javax.inject.Singleton
+
+
+@Singleton
+class MedtrumPumpPlugin @Inject constructor(
+ injector: HasAndroidInjector,
+ aapsLogger: AAPSLogger,
+ rh: ResourceHelper,
+ commandQueue: CommandQueue,
+ private val aapsSchedulers: AapsSchedulers,
+ private val rxBus: RxBus,
+ private val fabricPrivacy: FabricPrivacy,
+ private val dateUtil: DateUtil,
+ private val pumpSync: PumpSync,
+ private val uiInteraction: UiInteraction,
+ private val profileFunction: ProfileFunction
+) : PumpPluginBase(
+ PluginDescription()
+ .mainType(PluginType.PUMP) // TODO Prefs etc
+ .fragmentClass(MedtrumPumpFragment::class.java.name)
+ .pluginIcon(info.nightscout.core.ui.R.drawable.ic_eopatch2_128) // TODO
+ .pluginName(R.string.medtrum)
+ .shortName(R.string.medtrum_pump_shortname)
+ .preferencesId(R.xml.pref_medtrum_pump)
+ .description(R.string.medtrum_pump_description), injector, aapsLogger, rh, commandQueue
+), Pump {
+
+
+ override fun onStart() {
+ super.onStart()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ aapsLogger.debug(LTag.PUMP, "MedtrumPumpPlugin onStop()")
+ }
+
+ override fun isInitialized(): Boolean {
+ return false
+ }
+
+ override fun isSuspended(): Boolean {
+ return false
+ }
+
+ override fun isBusy(): Boolean {
+ return false
+ }
+
+ override fun isConnected(): Boolean {
+ return false
+ }
+
+ override fun isConnecting(): Boolean {
+ return false
+ }
+
+ override fun isHandshakeInProgress(): Boolean {
+ return false
+ }
+
+ override fun finishHandshaking() {
+ }
+
+ override fun connect(reason: String) {
+ aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
+ }
+
+ override fun disconnect(reason: String) {
+ aapsLogger.debug(LTag.PUMP, "Medtrum disconnect - reason:$reason")
+ }
+
+ override fun stopConnecting() {
+ }
+
+ override fun getPumpStatus(reason: String) {
+ }
+
+ override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
+ return PumpEnactResult(injector) // TODO
+ }
+
+ override fun isThisProfileSet(profile: Profile): Boolean {
+ return false // TODO
+ }
+
+ override fun lastDataTime(): Long {
+ return 0 // TODO
+ }
+
+ override val baseBasalRate: Double
+ get() = 0.0 // TODO
+
+ override val reservoirLevel: Double
+ get() = 0.0 // TODO
+
+ override val batteryLevel: Int
+ get() = 0 // TODO
+
+ override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
+ return PumpEnactResult(injector) // TODO
+ }
+
+ override fun stopBolusDelivering() {
+ // TODO
+ }
+
+ override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
+ return PumpEnactResult(injector) // TODO
+ }
+
+ override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
+ aapsLogger.info(LTag.PUMP, "setTempBasalPercent - percent: $percent, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
+ return PumpEnactResult(injector) // TODO
+ }
+
+ override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
+ aapsLogger.info(LTag.PUMP, "setExtendedBolus - insulin: $insulin, durationInMinutes: $durationInMinutes")
+ return PumpEnactResult(injector) // TODO
+ }
+
+ override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
+ return PumpEnactResult(injector) // TODO
+ }
+
+ override fun cancelExtendedBolus(): PumpEnactResult {
+ return PumpEnactResult(injector) // TODO
+ }
+
+ override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
+ return JSONObject() // TODO
+ }
+
+ override fun manufacturer(): ManufacturerType {
+ return ManufacturerType.Medtrum
+ }
+
+ override fun model(): PumpType {
+ return PumpType.GENERIC_AAPS // TODO
+ }
+
+ override fun serialNumber(): String {
+ return "0" // TODO
+ }
+
+ override val pumpDescription: PumpDescription
+ get() = PumpDescription(PumpType.GENERIC_AAPS) // TODO
+
+ override fun shortStatus(veryShort: Boolean): String {
+ return ""// TODO
+ }
+
+ override val isFakingTempsByExtendedBoluses: Boolean = false //TODO
+
+ override fun loadTDDs(): PumpEnactResult {
+ return PumpEnactResult(injector) // TODO
+ }
+
+ override fun canHandleDST(): Boolean {
+ return false
+ }
+
+ override fun getCustomActions(): List? {
+ return null
+ }
+
+ override fun executeCustomAction(customActionType: CustomActionType) {
+ }
+
+ override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? {
+ return null
+ }
+
+ override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
+ }
+
+ private fun readTBR(): PumpSync.PumpState.TemporaryBasal? {
+ return pumpSync.expectedPumpState().temporaryBasal // TODO
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt
new file mode 100644
index 0000000000..fb2f5a0296
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt
@@ -0,0 +1,14 @@
+package info.nightscout.pump.medtrum.di
+
+import dagger.Binds
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import info.nightscout.pump.medtrum.ui.MedtrumPumpFragment
+
+@Module
+@Suppress("unused")
+abstract class MedtrumPumpModule {
+
+ @ContributesAndroidInjector abstract fun contributesMedtrumPumpFragment(): MedtrumPumpFragment
+
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/events/EventMedtrumPumpUpdateGui.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/events/EventMedtrumPumpUpdateGui.kt
new file mode 100644
index 0000000000..e589f2131e
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/events/EventMedtrumPumpUpdateGui.kt
@@ -0,0 +1,5 @@
+package info.nightscout.pump.medtrum.events
+
+import info.nightscout.rx.events.EventUpdateGui
+
+class EventMedtrumPumpUpdateGui : EventUpdateGui()
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt
new file mode 100644
index 0000000000..8d3297c56c
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt
@@ -0,0 +1,103 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerThread
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import dagger.android.support.DaggerFragment
+import info.nightscout.core.extensions.toStringFull
+import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.interfaces.iob.IobCobCalculator
+import info.nightscout.interfaces.profile.ProfileFunction
+import info.nightscout.pump.medtrum.databinding.MedtrumPumpFragmentBinding
+import info.nightscout.pump.medtrum.events.EventMedtrumPumpUpdateGui
+import info.nightscout.pump.medtrum.MedtrumPumpPlugin
+import info.nightscout.rx.AapsSchedulers
+import info.nightscout.rx.bus.RxBus
+import info.nightscout.rx.events.EventExtendedBolusChange
+import info.nightscout.rx.events.EventTempBasalChange
+import info.nightscout.shared.interfaces.ResourceHelper
+import info.nightscout.shared.utils.DateUtil
+import info.nightscout.shared.utils.T
+import io.reactivex.rxjava3.disposables.CompositeDisposable
+import io.reactivex.rxjava3.kotlin.plusAssign
+import javax.inject.Inject
+
+class MedtrumPumpFragment : DaggerFragment() {
+
+ @Inject lateinit var rxBus: RxBus
+ @Inject lateinit var rh: ResourceHelper
+ @Inject lateinit var dateUtil: DateUtil
+ @Inject lateinit var fabricPrivacy: FabricPrivacy
+ @Inject lateinit var medtrumPumpPlugin: MedtrumPumpPlugin
+ @Inject lateinit var profileFunction: ProfileFunction
+ @Inject lateinit var iobCobCalculator: IobCobCalculator
+ @Inject lateinit var aapsSchedulers: AapsSchedulers
+
+ private val disposable = CompositeDisposable()
+
+ private lateinit var refreshLoop: Runnable
+ private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
+
+ private var _binding: MedtrumPumpFragmentBinding? = null
+
+ // This property is only valid between onCreateView and
+ // onDestroyView.
+ private val binding get() = _binding!!
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ MedtrumPumpFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+ disposable += rxBus
+ .toObservable(EventMedtrumPumpUpdateGui::class.java)
+ .observeOn(aapsSchedulers.main)
+ .subscribe({ updateGui() }, fabricPrivacy::logException)
+ disposable += rxBus
+ .toObservable(EventTempBasalChange::class.java)
+ .observeOn(aapsSchedulers.main)
+ .subscribe({ updateGui() }, fabricPrivacy::logException)
+ disposable += rxBus
+ .toObservable(EventExtendedBolusChange::class.java)
+ .observeOn(aapsSchedulers.main)
+ .subscribe({ updateGui() }, fabricPrivacy::logException)
+ refreshLoop = Runnable {
+ activity?.runOnUiThread { updateGui() }
+ handler.postDelayed(refreshLoop, T.mins(1).msecs())
+ }
+ handler.postDelayed(refreshLoop, T.mins(1).msecs())
+ updateGui()
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ handler.removeCallbacksAndMessages(null)
+ }
+
+ @Synchronized
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+ @Synchronized
+ private fun updateGui() {
+ if (_binding == null) return
+ val profile = profileFunction.getProfile() ?: return
+ binding.baseBasalRate.text = rh.gs(info.nightscout.core.ui.R.string.pump_base_basal_rate, medtrumPumpPlugin.baseBasalRate)
+ binding.tempbasal.text = iobCobCalculator.getTempBasal(dateUtil.now())?.toStringFull(profile, dateUtil)
+ ?: ""
+ binding.extendedbolus.text = iobCobCalculator.getExtendedBolus(dateUtil.now())?.toStringFull(dateUtil)
+ ?: ""
+ binding.battery.text = rh.gs(info.nightscout.core.ui.R.string.format_percent, 0) // TODO
+ binding.reservoir.text = rh.gs(info.nightscout.interfaces.R.string.format_insulin_units, 0.0) // TODO
+
+ binding.serialNumber.text = medtrumPumpPlugin.serialNumber()
+ }
+}
diff --git a/pump/medtrum/src/main/res/layout/medtrum_pump_fragment.xml b/pump/medtrum/src/main/res/layout/medtrum_pump_fragment.xml
new file mode 100644
index 0000000000..222bed82df
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/medtrum_pump_fragment.xml
@@ -0,0 +1,306 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..b361dec76e
--- /dev/null
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -0,0 +1,17 @@
+
+
+
+ snInput
+ medtrumpump_settings
+
+
+ Medtrum
+ MEDTRUM
+ Medtrum Nano
+ MEDTRUM
+ Medtrum pump settings
+
+ SN
+ Serial number pump base
+
+
diff --git a/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml b/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
new file mode 100644
index 0000000000..9b40fc9864
--- /dev/null
+++ b/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
new file mode 100644
index 0000000000..4fd2aef548
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
@@ -0,0 +1,37 @@
+package info.nightscout.androidaps
+
+import info.nightscout.rx.AapsSchedulers
+import info.nightscout.rx.TestAapsSchedulers
+import info.nightscout.rx.logging.AAPSLoggerTest
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.extension.ExtendWith
+import org.mockito.Mockito
+import org.mockito.junit.jupiter.MockitoExtension
+import org.mockito.junit.jupiter.MockitoSettings
+import org.mockito.quality.Strictness
+import java.util.Locale
+
+@ExtendWith(MockitoExtension::class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+open class TestBase {
+
+ val aapsLogger = AAPSLoggerTest()
+ val aapsSchedulers: AapsSchedulers = TestAapsSchedulers()
+
+ @BeforeEach
+ fun setupLocale() {
+ Locale.setDefault(Locale.ENGLISH)
+ System.setProperty("disableFirebase", "true")
+ }
+
+ // Workaround for Kotlin nullability.
+ // https://medium.com/@elye.project/befriending-kotlin-and-mockito-1c2e7b0ef791
+ // https://stackoverflow.com/questions/30305217/is-it-possible-to-use-mockito-in-kotlin
+ fun anyObject(): T {
+ Mockito.any()
+ return uninitialized()
+ }
+
+ @Suppress("Unchecked_Cast")
+ fun uninitialized(): T = null as T
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 137cc8c2bd..24a3acf745 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -33,6 +33,7 @@ include ':pump:diaconn'
include ':pump:eopatch'
include ':pump:eopatch-core'
include ':insight'
+include ':pump:medtrum'
include ':pump:medtronic'
include ':pump:omnipod-common'
include ':pump:omnipod-eros'
From 37a6fa92208661540d87c782bb1ddfb328ac7115 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 18 Feb 2023 21:10:50 +0100
Subject: [PATCH 002/116] Added Medtrum pump type etc
---
.../interfaces/pump/defs/PumpCapability.kt | 1 +
.../interfaces/pump/defs/PumpType.kt | 21 +++++++++++++++++++
.../nightscout/core/pump/PumpTypeExtension.kt | 2 ++
.../entities/embedments/InterfaceIDs.kt | 1 +
.../pump/medtrum/MedtrumPumpPlugin.kt | 6 ++++--
5 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpCapability.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpCapability.kt
index ed9620a818..f425ffdff7 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpCapability.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpCapability.kt
@@ -26,6 +26,7 @@ enum class PumpCapability {
YpsomedCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), // BasalRates (separately grouped)
DiaconnCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), //
EopatchCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, BasalRate30min)),
+ MedtrumCapabilities(arrayOf(Bolus, TempBasal, BasalProfileSet, BasalRate30min)), // Technically the pump supports ExtendedBolus, but not implemented (yet)
BasalRate_Duration15minAllowed,
BasalRate_Duration30minAllowed,
BasalRate_Duration15and30minAllowed(arrayOf(BasalRate_Duration15minAllowed, BasalRate_Duration30minAllowed)),
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
index 30163c9ddf..4199af95a8 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
@@ -391,6 +391,26 @@ enum class PumpType {
isPatchPump = true,
maxReservoirReading = 50,
source = Source.EOPatch2
+ ),
+
+ //Medtrum Nano Pump
+ MEDTRUM_NANO(
+ description = "Medtrum Nano",
+ manufacturer = ManufacturerType.Medtrum,
+ model = "Nano",
+ bolusSize = 0.05,
+ specialBolusSize = null,
+ extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05, 30.0),
+ pumpTempBasalType = PumpTempBasalType.Absolute,
+ tbrSettings = DoseSettings(0.05, 30, 12 * 60, 0.0, 25.0),
+ specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed,
+ baseBasalMinValue = 0.05,
+ baseBasalMaxValue = 25.0,
+ baseBasalStep = 0.05,
+ baseBasalSpecialSteps = null,
+ pumpCapability = PumpCapability.MedtrumCapabilities,
+ isPatchPump = true,
+ source = Source.Medtrum
);
val description: String
@@ -458,6 +478,7 @@ enum class PumpType {
OmnipodEros,
OmnipodDash,
EOPatch2,
+ Medtrum,
MDI,
VirtualPump,
Unknown
diff --git a/core/main/src/main/java/info/nightscout/core/pump/PumpTypeExtension.kt b/core/main/src/main/java/info/nightscout/core/pump/PumpTypeExtension.kt
index 7024036f9e..8a0b120cc1 100644
--- a/core/main/src/main/java/info/nightscout/core/pump/PumpTypeExtension.kt
+++ b/core/main/src/main/java/info/nightscout/core/pump/PumpTypeExtension.kt
@@ -59,6 +59,7 @@ fun PumpType.Companion.fromDbPumpType(pt: InterfaceIDs.PumpType): PumpType =
InterfaceIDs.PumpType.USER -> PumpType.USER
InterfaceIDs.PumpType.DIACONN_G8 -> PumpType.DIACONN_G8
InterfaceIDs.PumpType.EOPATCH2 -> PumpType.EOFLOW_EOPATCH2
+ InterfaceIDs.PumpType.MEDTRUM -> PumpType.MEDTRUM_NANO
InterfaceIDs.PumpType.CACHE -> PumpType.CACHE
}
@@ -117,5 +118,6 @@ fun PumpType.toDbPumpType(): InterfaceIDs.PumpType =
PumpType.USER -> InterfaceIDs.PumpType.USER
PumpType.DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8
PumpType.EOFLOW_EOPATCH2 -> InterfaceIDs.PumpType.EOPATCH2
+ PumpType.MEDTRUM_NANO -> InterfaceIDs.PumpType.MEDTRUM
PumpType.CACHE -> InterfaceIDs.PumpType.CACHE
}
diff --git a/database/entities/src/main/java/info/nightscout/database/entities/embedments/InterfaceIDs.kt b/database/entities/src/main/java/info/nightscout/database/entities/embedments/InterfaceIDs.kt
index 5f78da4e8c..a10a7740cd 100644
--- a/database/entities/src/main/java/info/nightscout/database/entities/embedments/InterfaceIDs.kt
+++ b/database/entities/src/main/java/info/nightscout/database/entities/embedments/InterfaceIDs.kt
@@ -43,6 +43,7 @@ data class InterfaceIDs(
MDI,
DIACONN_G8,
EOPATCH2,
+ MEDTRUM,
USER,
CACHE;
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
index 1d2e4c0742..404668c68f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
@@ -64,6 +64,8 @@ class MedtrumPumpPlugin @Inject constructor(
.description(R.string.medtrum_pump_description), injector, aapsLogger, rh, commandQueue
), Pump {
+ private var mPumpType: PumpType = PumpType.MEDTRUM_NANO
+ private val mPumpDescription = PumpDescription(mPumpType)
override fun onStart() {
super.onStart()
@@ -175,7 +177,7 @@ class MedtrumPumpPlugin @Inject constructor(
}
override fun model(): PumpType {
- return PumpType.GENERIC_AAPS // TODO
+ return mPumpType
}
override fun serialNumber(): String {
@@ -183,7 +185,7 @@ class MedtrumPumpPlugin @Inject constructor(
}
override val pumpDescription: PumpDescription
- get() = PumpDescription(PumpType.GENERIC_AAPS) // TODO
+ get() = mPumpDescription
override fun shortStatus(veryShort: Boolean): String {
return ""// TODO
From b635ad26d85585b89ee728207602d9dd46c9bfee Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 19 Feb 2023 20:09:52 +0100
Subject: [PATCH 003/116] Initial Medtrum BLEComm
---
pump/medtrum/build.gradle | 2 +-
.../pump/medtrum/MedtrumPumpPlugin.kt | 2 +-
.../pump/medtrum/comm/ManufacturerData.kt | 36 ++
.../pump/medtrum/comm/WriteCommandPackets.kt | 79 ++++
.../pump/medtrum/di/MedtrumPumpModule.kt | 2 +-
.../pump/medtrum/encryption/Crypt.kt | 75 ++++
.../events/EventMedtrumPumpUpdateGui.kt | 2 +-
.../medtrum/extension/ByteArrayExtension.kt | 28 ++
.../pump/medtrum/extension/IntExtension.kt | 10 +
.../pump/medtrum/extension/LongExtension.kt | 10 +
.../pump/medtrum/services/BLEComm.kt | 399 ++++++++++++++++++
.../info/nightscout/androidaps/TestBase.kt | 2 +-
.../medtrum/comm/WriteCommandPacketsTest.kt | 90 ++++
.../pump/medtrum/encryption/CryptTest.kt | 27 ++
14 files changed, 759 insertions(+), 5 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ManufacturerData.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/ByteArrayExtension.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/IntExtension.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/LongExtension.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/WriteCommandPacketsTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/encryption/CryptTest.kt
diff --git a/pump/medtrum/build.gradle b/pump/medtrum/build.gradle
index 39d231800f..9163baf95a 100644
--- a/pump/medtrum/build.gradle
+++ b/pump/medtrum/build.gradle
@@ -24,4 +24,4 @@ dependencies {
implementation project(':core:main')
implementation project(':core:ui')
implementation project(':core:utils')
-}
\ No newline at end of file
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
index 404668c68f..8cd141e446 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
@@ -218,4 +218,4 @@ class MedtrumPumpPlugin @Inject constructor(
private fun readTBR(): PumpSync.PumpState.TemporaryBasal? {
return pumpSync.expectedPumpState().temporaryBasal // TODO
}
-}
\ No newline at end of file
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ManufacturerData.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ManufacturerData.kt
new file mode 100644
index 0000000000..d567feb1ba
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ManufacturerData.kt
@@ -0,0 +1,36 @@
+package info.nightscout.pump.medtrum.comm
+
+import kotlin.experimental.and
+import info.nightscout.pump.medtrum.extension.toLong
+
+class ManufacturerData(private val manufacturerDataBytes: ByteArray) {
+ private var deviceID: Long = 0
+ private var deviceType = 0
+ private var version = 0
+
+ init {
+ setData(manufacturerDataBytes)
+ }
+
+ fun setData(inputData: ByteArray) {
+ var index = 0
+ val deviceIDBytes: ByteArray = manufacturerDataBytes.copyOfRange(index, index + 4)
+ deviceID = deviceIDBytes.toLong()
+ index += 4
+ deviceType = (manufacturerDataBytes[index] and 0xff.toByte()).toInt()
+ index += 1
+ version = (manufacturerDataBytes[index] and 0xff.toByte()).toInt()
+ }
+
+ fun getDeviceID(): Long{
+ return deviceID
+ }
+
+ fun getDeviceType(): Int {
+ return deviceType
+ }
+
+ fun getVersion(): Int {
+ return version
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
new file mode 100644
index 0000000000..517072f8d6
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
@@ -0,0 +1,79 @@
+package info.nightscout.pump.medtrum.comm
+
+import info.nightscout.pump.medtrum.encryption.Crypt
+
+
+class WriteCommandPackets(private val command: ByteArray) {
+
+ val crypt = Crypt()
+
+ private val packages = mutableListOf()
+ private var index = 0
+ private var writeCommandIndex = 0
+ private var allPacketsConsumed = false
+
+
+ init {
+ setData(command)
+ }
+
+ fun setData(inputData: ByteArray) {
+ resetPackets()
+ // PackageIndex: 0 initially, if there are multiple packet, for the first packet it is set to 0 (not included in crc calc but sent in actual header)
+ var pkgIndex = 0
+ var header = byteArrayOf(
+ (inputData.size + 4).toByte(),
+ inputData[0],
+ writeCommandIndex.toByte(),
+ pkgIndex.toByte()
+ )
+
+ var tmp: ByteArray = header + inputData.copyOfRange(1, inputData.size)
+ var totalCommand: ByteArray = tmp + crypt.calcCrc8(tmp, tmp.size).toByte()
+
+ if ((totalCommand.size - header.size) <= 15) {
+ packages.add(totalCommand + 0.toByte())
+ } else {
+ pkgIndex = 1
+ var remainingCommand = totalCommand.copyOfRange(4, totalCommand.size)
+
+ while (remainingCommand.size > 15) {
+ header[3] = pkgIndex.toByte()
+ tmp = header + remainingCommand.copyOfRange(0, 15)
+ packages.add(tmp + crypt.calcCrc8(tmp, tmp.size).toByte())
+
+ remainingCommand = remainingCommand.copyOfRange(15, remainingCommand.size)
+ pkgIndex = (pkgIndex + 1) % 256
+ }
+
+ // Add last package
+ header[3] = pkgIndex.toByte()
+ tmp = header + remainingCommand
+ packages.add(tmp + crypt.calcCrc8(tmp, tmp.size).toByte())
+ }
+ writeCommandIndex = (writeCommandIndex % 255) + 1
+ }
+
+
+ fun allPacketsConsumed(): Boolean {
+ return allPacketsConsumed
+ }
+
+ fun getNextPacket(): ByteArray? {
+ var ret: ByteArray? = null
+ if (index < packages.size) {
+ ret = packages[index]
+ index++
+ }
+ if (index >= packages.size) {
+ allPacketsConsumed = true
+ }
+ return ret
+ }
+
+ private fun resetPackets() {
+ packages.clear()
+ index = 0
+ allPacketsConsumed = false
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt
index fb2f5a0296..9589839625 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt
@@ -11,4 +11,4 @@ abstract class MedtrumPumpModule {
@ContributesAndroidInjector abstract fun contributesMedtrumPumpFragment(): MedtrumPumpFragment
-}
\ No newline at end of file
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
new file mode 100644
index 0000000000..093c3a8c12
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
@@ -0,0 +1,75 @@
+package info.nightscout.pump.medtrum.encryption
+
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.extension.toLong
+
+class Crypt {
+ val RIJNDEAL_S_BOX: IntArray = intArrayOf(99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22)
+ val RIJNDEAL_INVERSE_S_BOX: IntArray = intArrayOf(82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125)
+ val CRC_8_TABLE: IntArray = intArrayOf(0, 155, 173, 54, 193, 90, 108, 247, 25, 130, 180, 47, 216, 67, 117, 238, 50, 169, 159, 4, 243, 104, 94, 197, 43, 176, 134, 29, 234, 113, 71, 220, 100, 255, 201, 82, 165, 62, 8, 147, 125, 230, 208, 75, 188, 39, 17, 138, 86, 205, 251, 96, 151, 12, 58, 161, 79, 212, 226, 121, 142, 21, 35, 184, 200, 83, 101, 254, 9, 146, 164, 63, 209, 74, 124, 231, 16, 139, 189, 38, 250, 97, 87, 204, 59, 160, 150, 13, 227, 120, 78, 213, 34, 185, 143, 20, 172, 55, 1, 154, 109, 246, 192, 91, 181, 46, 24, 131, 116, 239, 217, 66, 158, 5, 51, 168, 95, 196, 242, 105, 135, 28, 42, 177, 70, 221, 235, 112, 11, 144, 166, 61, 202, 81, 103, 252, 18, 137, 191, 36, 211, 72, 126, 229, 57, 162, 148, 15, 248, 99, 85, 206, 32, 187, 141, 22, 225, 122, 76, 215, 111, 244, 194, 89, 174, 53, 3, 152, 118, 237, 219, 64, 183, 44, 26, 129, 93, 198, 240, 107, 156, 7, 49, 170, 68, 223, 233, 114, 133, 30, 40, 179, 195, 88, 110, 245, 2, 153, 175, 52, 218, 65, 119, 236, 27, 128, 182, 45, 241, 106, 92, 199, 48, 171, 157, 6, 232, 115, 69, 222, 41, 178, 132, 31, 167, 60, 10, 145, 102, 253, 203, 80, 190, 37, 19, 136, 127, 228, 210, 73, 149, 14, 56, 163, 84, 207, 249, 98, 140, 23, 33, 186, 77, 214, 224, 123)
+
+ val MED_CIPHER: Long = 1344751489
+
+ fun keyGen(input: Long): Long {
+ val key = randomGen(randomGen(MED_CIPHER xor input))
+ return simpleCrypt(key)
+ }
+
+ fun randomGen(input: Long): Long {
+ val A = 16807
+ val Q = 127773
+ val R = 2836
+ val tmp1 = input / Q
+ var ret = (input - (tmp1 * Q)) * A - (tmp1 * R)
+ if (ret < 0) {
+ ret += 2147483647L
+ }
+ return ret
+ }
+
+ fun calcCrc8(value: ByteArray, size: Int): Int {
+ var crc8 = 0
+ for (i in 0 until size) {
+ crc8 = CRC_8_TABLE[(value[i].toInt() and 255) xor (crc8 and 255)].toInt() and 255
+ }
+ return crc8
+ }
+
+ private fun simpleCrypt(inputData: Long): Long {
+ var temp = inputData xor MED_CIPHER
+ for (i in 0 until 32) {
+ temp = changeByTable(rotatoLeft(temp, 32, 1), RIJNDEAL_S_BOX).toLong()
+ }
+ return temp
+ }
+
+ fun simpleDecrypt(inputData: Long): Long {
+ var temp = inputData
+ for (i in 0 until 32) {
+ temp = rotatoRight(changeByTable(temp, RIJNDEAL_INVERSE_S_BOX), 32, 1).toLong()
+ }
+ return temp xor MED_CIPHER
+ }
+
+ private fun changeByTable(inputData: Long, tableData: IntArray): Long {
+ val value = inputData.toByteArray(4)
+ val results = ByteArray(4)
+
+ for (i in value.indices) {
+ var byte = value[i].toInt()
+ if (byte < 0) {
+ byte += 256
+ }
+ results[i] = tableData[byte].toByte()
+ }
+ return results.toLong()
+ }
+
+ private fun rotatoLeft(x: Long, s: Int, n: Int): Long {
+ return (x shl n) or (x ushr (s - n))
+ }
+
+ private fun rotatoRight(x: Long, s: Int, n: Int): Int {
+ return (x ushr n or (x shl (s - n))).toInt()
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/events/EventMedtrumPumpUpdateGui.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/events/EventMedtrumPumpUpdateGui.kt
index e589f2131e..e93896d063 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/events/EventMedtrumPumpUpdateGui.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/events/EventMedtrumPumpUpdateGui.kt
@@ -2,4 +2,4 @@ package info.nightscout.pump.medtrum.events
import info.nightscout.rx.events.EventUpdateGui
-class EventMedtrumPumpUpdateGui : EventUpdateGui()
\ No newline at end of file
+class EventMedtrumPumpUpdateGui : EventUpdateGui()
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/ByteArrayExtension.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/ByteArrayExtension.kt
new file mode 100644
index 0000000000..0aa4a100b1
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/ByteArrayExtension.kt
@@ -0,0 +1,28 @@
+package info.nightscout.pump.medtrum.extension
+
+/** Extensions for different types of conversions needed when doing stuff with bytes */
+fun ByteArray.toLong(): Long {
+ require(this.size <= 8) {
+ "Array size must be <= 8 for 'toLong' conversion operation"
+ }
+ var result = 0L
+ for (i in this.indices) {
+ val byte = this[i]
+ val shifted = (byte.toInt() and 0xFF).toLong() shl 8 * i
+ result = result or shifted
+ }
+ return result
+}
+
+fun ByteArray.toInt(): Int {
+ require(this.size <= 4) {
+ "Array size must be <= 4 for 'toInt' conversion operation"
+ }
+ var result = 0
+ for (i in this.indices) {
+ val byte = this[i]
+ val shifted = (byte.toInt() and 0xFF).toInt() shl 8 * i
+ result = result or shifted
+ }
+ return result
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/IntExtension.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/IntExtension.kt
new file mode 100644
index 0000000000..8589496e18
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/IntExtension.kt
@@ -0,0 +1,10 @@
+package info.nightscout.pump.medtrum.extension
+
+/** Extensions for different types of conversions needed when doing stuff with bytes */
+fun Int.toByteArray(byteLength: Int): ByteArray {
+ val bytes = ByteArray(byteLength)
+ for (i in 0 until byteLength) {
+ bytes[i] = (this shr (i * 8) and 0xFF).toByte()
+ }
+ return bytes
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/LongExtension.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/LongExtension.kt
new file mode 100644
index 0000000000..a294670ec1
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/LongExtension.kt
@@ -0,0 +1,10 @@
+package info.nightscout.pump.medtrum.extension
+
+/** Extensions for different types of conversions needed when doing stuff with bytes */
+fun Long.toByteArray(byteLength: Int): ByteArray {
+ val bytes = ByteArray(byteLength)
+ for (i in 0 until byteLength) {
+ bytes[i] = (this shr (i * 8) and 0xFF).toByte()
+ }
+ return bytes
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
new file mode 100644
index 0000000000..700bc49266
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -0,0 +1,399 @@
+package info.nightscout.pump.medtrum.services
+
+import android.Manifest
+import android.annotation.SuppressLint
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothGatt
+import android.bluetooth.BluetoothGattCallback
+import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattDescriptor
+import android.bluetooth.BluetoothGattService
+import android.bluetooth.BluetoothManager
+import android.bluetooth.BluetoothProfile
+import android.bluetooth.le.ScanCallback
+import android.bluetooth.le.ScanResult
+import android.bluetooth.le.ScanSettings
+import android.bluetooth.le.ScanFilter
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.SystemClock
+import androidx.core.app.ActivityCompat
+import dagger.android.HasAndroidInjector
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.core.utils.notify
+import info.nightscout.core.utils.waitMillis
+import info.nightscout.interfaces.notifications.Notification
+import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.ui.UiInteraction
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.encryption.Crypt
+import info.nightscout.pump.medtrum.comm.WriteCommandPackets
+import info.nightscout.pump.medtrum.comm.ManufacturerData
+import info.nightscout.rx.bus.RxBus
+import info.nightscout.rx.events.EventDismissNotification
+import info.nightscout.rx.events.EventPumpStatusChanged
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.interfaces.ResourceHelper
+import info.nightscout.shared.sharedPreferences.SP
+import info.nightscout.shared.utils.DateUtil
+import java.util.UUID
+import java.util.Arrays
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class BLEComm @Inject internal constructor(
+ private val injector: HasAndroidInjector,
+ private val aapsLogger: AAPSLogger,
+ private val rh: ResourceHelper,
+ private val context: Context,
+ private val rxBus: RxBus,
+ private val sp: SP,
+ private val pumpSync: PumpSync,
+ private val dateUtil: DateUtil,
+ private val uiInteraction: UiInteraction
+) {
+
+ companion object {
+
+ private const val WRITE_DELAY_MILLIS: Long = 50
+ private const val SERVICE_UUID = "669A9001-0008-968F-E311-6050405558B3"
+ private const val READ_UUID = "669a9120-0008-968f-e311-6050405558b3"
+ private const val WRITE_UUID = "669a9101-0008-968f-e311-6050405558b"
+ private const val CHARACTERISTIC_CONFIG_UUID = "00002902-0000-1000-8000-00805f9b34fb"
+
+ private const val MANUFACTURER_ID = 18305
+ private const val COMMAND_AUTH_REQ: Byte = 5
+ }
+
+ private val mBluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
+ private var mBluetoothGatt: BluetoothGatt? = null
+ private val mCrypt = Crypt()
+
+ var isConnected = false
+ var isConnecting = false
+ private var uartWrite: BluetoothGattCharacteristic? = null
+
+ private var deviceID: Long = 0
+
+ /** Connect flow: 1. Start scanning for our device (SN entered in settings) */
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ fun startScan(): Boolean {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
+ ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED
+ ) {
+ ToastUtils.errorToast(context, context.getString(info.nightscout.core.ui.R.string.need_connect_permission))
+ aapsLogger.error(LTag.PUMPBTCOMM, "missing permissions")
+ return false
+ }
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Start scan!!")
+ val settings = ScanSettings.Builder()
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+ .build()
+ val filters = mutableListOf()
+
+ if (deviceID == 0.toLong()) deviceID = rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput).toLong(radix = 16)
+
+ isConnected = false
+ // TODO: Maybe replace this by (or add) a isScanning parameter?
+ isConnecting = true
+
+ // Find our Medtrum Device!
+ filters.add(
+ ScanFilter.Builder().setDeviceName("MT").build()
+ )
+ // TODO Check if we need to add MAC for reconnects? Not sure if otherwise we can find the device
+ mBluetoothAdapter?.bluetoothLeScanner?.startScan(filters, settings, mScanCallback)
+ return true
+ }
+
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ fun stopScan() {
+ mBluetoothAdapter?.bluetoothLeScanner?.stopScan(mScanCallback)
+ }
+
+ /** Connect flow: 2. When device is found this is called by onScanResult() */
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ fun connect(device: BluetoothDevice) {
+ mBluetoothGatt =
+ device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
+ }
+
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ fun disconnect() {
+ mBluetoothGatt?.disconnect()
+ mBluetoothGatt = null
+ }
+
+ @Synchronized
+ fun stopConnecting() {
+ isConnecting = false
+ }
+
+ @SuppressLint("MissingPermission")
+ @Synchronized fun close() {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "BluetoothAdapter close")
+ mBluetoothGatt?.close()
+ mBluetoothGatt = null
+ }
+
+ /** Scan callback */
+ private val mScanCallback: ScanCallback = object : ScanCallback() {
+ override fun onScanResult(callbackType: Int, result: ScanResult) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "OnScanResult!" + result)
+ super.onScanResult(callbackType, result)
+
+ val manufacturerData =
+ result.scanRecord?.getManufacturerSpecificData(MANUFACTURER_ID)
+ ?.let { ManufacturerData(it) }
+
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Found DeviceID: " + manufacturerData?.getDeviceID())
+
+ if (manufacturerData?.getDeviceID() == deviceID) {
+ stopScan()
+ connect(result.device)
+ }
+ }
+
+ override fun onScanFailed(errorCode: Int) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Scan FAILED!")
+ }
+ }
+
+ @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
+ private val mGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
+ override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
+ onConnectionStateChangeSynchronized(gatt, status, newState) // call it synchronized
+ }
+
+ override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onServicesDiscovered")
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ findCharacteristic()
+ }
+ }
+
+ override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicRead status = " + status)
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ readDataParsing(characteristic.value)
+ }
+ }
+
+ override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged")
+ readDataParsing(characteristic.value)
+ }
+
+ override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite status = " + status)
+ // TODO (note also queue, note that in danars there is no response, so check where to handle multiple packets)
+ // aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value))
+ // Thread {
+ // synchronized(mSendQueue) {
+ // // after message sent, check if there is the rest of the message waiting and send it
+ // if (mSendQueue.size > 0) {
+ // val bytes = mSendQueue[0]
+ // mSendQueue.removeAt(0)
+ // writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
+ // }
+ // }
+ // }.start()
+ }
+
+ override fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) {
+ super.onDescriptorWrite(gatt, descriptor, status)
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onDescriptorWrite " + status)
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ readDescriptor(descriptor)
+ }
+ }
+
+ /** Connect flow: 5. Notifications enabled read descriptor to verify and start auth process*/
+ override fun onDescriptorRead(
+ gatt: BluetoothGatt,
+ descriptor: BluetoothGattDescriptor,
+ status: Int
+ ) {
+ super.onDescriptorRead(gatt, descriptor, status)
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onDescriptorRead status: " + status)
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ checkDescriptor(descriptor)
+ }
+ }
+
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun readDescriptor(descriptor: BluetoothGattDescriptor?) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "readDescriptor")
+ if (mBluetoothAdapter == null || mBluetoothGatt == null || descriptor == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return
+ }
+ mBluetoothGatt?.readDescriptor(descriptor)
+ }
+
+ private fun checkDescriptor(descriptor: BluetoothGattDescriptor) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "checkDescriptor")
+ val service = getGattService()
+ if (mBluetoothAdapter == null || mBluetoothGatt == null || service == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return
+ }
+ if (descriptor.value.toInt() > 0) {
+ var notificationEnabled = true
+ val characteristics = service.characteristics
+ for (j in 0 until characteristics.size) {
+ val configDescriptor =
+ characteristics[j].getDescriptor(UUID.fromString(CHARACTERISTIC_CONFIG_UUID))
+ if (configDescriptor.value == null || configDescriptor.value.toInt() <= 0) {
+ notificationEnabled = false
+ }
+ }
+ if (notificationEnabled) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Notifications enabled!")
+ authorize()
+ }
+ }
+ }
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun setCharacteristicNotification(characteristic: BluetoothGattCharacteristic?, enabled: Boolean) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "setCharacteristicNotification")
+ if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return
+ }
+ mBluetoothGatt?.setCharacteristicNotification(characteristic, enabled)
+ characteristic?.getDescriptor(UUID.fromString(CHARACTERISTIC_CONFIG_UUID))?.let {
+ if (characteristic.properties and 0x10 > 0) {
+ it.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
+ mBluetoothGatt?.writeDescriptor(it)
+ } else if (characteristic.properties and 0x20 > 0) {
+ it.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
+ mBluetoothGatt?.writeDescriptor(it)
+ } else {
+
+ }
+ }
+ }
+
+ /** Connect flow: 3. When we are connected discover services*/
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun onConnectionStateChangeSynchronized(gatt: BluetoothGatt, status: Int, newState: Int) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange newState: " + newState + " status: " + status)
+ if (newState == BluetoothProfile.STATE_CONNECTED) {
+ gatt.discoverServices()
+ } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+ close()
+ isConnected = false
+ isConnecting = false
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
+ disconnect()
+ startScan()
+ }
+ }
+
+ private fun readDataParsing(receivedData: ByteArray) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "<<>> " + Arrays.toString(receivedData))
+ // TODO
+ /** Connect flow: 6. Authorized */ // TODO place this at the correct place
+ }
+
+ private fun authorize() {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Start auth!")
+ val role = 2 // Fixed to 2 for pump
+ val key = mCrypt.keyGen(deviceID)
+ val commandData = byteArrayOf(COMMAND_AUTH_REQ) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4)
+ sendMessage(commandData)
+ }
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun sendMessage(message: ByteArray) {
+ // TODO: Handle packages which consist of multiple, Create a queue of packages
+ aapsLogger.debug(LTag.PUMPBTCOMM, "sendMessage message = " + Arrays.toString(message))
+ val writePacket = WriteCommandPackets(message)
+ val value: ByteArray? = writePacket.getNextPacket()
+
+ // TODO: queue
+ writeCharacteristic(uartWriteBTGattChar, value)
+ }
+
+ private fun getGattService(): BluetoothGattService? {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "getGattService")
+ if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return null
+ }
+ return mBluetoothGatt?.getService(UUID.fromString(SERVICE_UUID))
+ }
+
+ private fun getGattCharacteristic(uuid: UUID): BluetoothGattCharacteristic? {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "getGattCharacteristic $uuid")
+ val service = getGattService()
+ if (mBluetoothAdapter == null || mBluetoothGatt == null || service == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return null
+ }
+ return service.getCharacteristic(uuid)
+ }
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun writeCharacteristic(characteristic: BluetoothGattCharacteristic, data: ByteArray?) {
+ Thread(Runnable {
+ SystemClock.sleep(WRITE_DELAY_MILLIS)
+ if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return@Runnable
+ }
+ characteristic.value = data
+ characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
+ aapsLogger.debug("writeCharacteristic:" + Arrays.toString(data))
+ mBluetoothGatt?.writeCharacteristic(characteristic)
+ }).start()
+ SystemClock.sleep(WRITE_DELAY_MILLIS)
+ }
+
+ private val uartWriteBTGattChar: BluetoothGattCharacteristic
+ get() = uartWrite
+ ?: BluetoothGattCharacteristic(UUID.fromString(WRITE_UUID), BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, 0).also { uartWrite = it }
+
+ /** Connect flow: 4. When services are discovered find characteristics and set notifications*/
+ private fun findCharacteristic() {
+ val gattService = getGattService() ?: return
+ val gattCharacteristics = gattService.characteristics
+ for (gattCharacteristic in gattCharacteristics) {
+ setCharacteristicNotification(gattCharacteristic, true)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
index 4fd2aef548..96af831f2b 100644
--- a/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
@@ -34,4 +34,4 @@ open class TestBase {
@Suppress("Unchecked_Cast")
fun uninitialized(): T = null as T
-}
\ No newline at end of file
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/WriteCommandPacketsTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/WriteCommandPacketsTest.kt
new file mode 100644
index 0000000000..10d05c2ad6
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/WriteCommandPacketsTest.kt
@@ -0,0 +1,90 @@
+package info.nightscout.pump.medtrum.comm
+
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class WriteCommandPacketsTest {
+
+ @Test
+ fun Given14LongCommandExpectOnePacket() {
+ val input = byteArrayOf(5, 2, 0, 0, 0, 0, -21, 57, -122, -56)
+ val expect = byteArrayOf(14, 5, 0, 0, 2, 0, 0, 0, 0, -21, 57, -122, -56, -93, 0)
+ val cmdPackets = WriteCommandPackets(input)
+ val output = cmdPackets.getNextPacket()
+
+ assertEquals(expect.contentToString(), output.contentToString())
+ }
+
+ @Test
+ fun Given41LongCommandExpectThreePackets() {
+ val input = byteArrayOf(18, 0, 12, 0, 3, 0, 1, 30, 32, 3, 16, 14, 0, 0, 1, 7, 0, -96, 2, -16, 96, 2, 104, 33, 2, -32, -31, 1, -64, 3, 2, -20, 36, 2, 100, -123, 2)
+ val expect1 = byteArrayOf(41, 18, 0, 1, 0, 12, 0, 3, 0, 1, 30, 32, 3, 16, 14, 0, 0, 1, 7, -121)
+ val expect2 = byteArrayOf(41, 18, 0, 2, 0, -96, 2, -16, 96, 2, 104, 33, 2, -32, -31, 1, -64, 3, 2, -3)
+ val expect3 = byteArrayOf(41, 18, 0, 3, -20, 36, 2, 100, -123, 2, -125, -89)
+
+ val cmdPackets = WriteCommandPackets(input)
+ val output1 = cmdPackets.getNextPacket()
+ val output2 = cmdPackets.getNextPacket()
+ val output3 = cmdPackets.getNextPacket()
+ val output4 = cmdPackets.getNextPacket()
+
+
+ assertEquals(expect1.contentToString(), output1.contentToString())
+ assertEquals(expect2.contentToString(), output2.contentToString())
+ assertEquals(expect3.contentToString(), output3.contentToString())
+ assertNull(output4)
+ assertEquals(true, cmdPackets.allPacketsConsumed())
+
+ }
+
+ @Test
+ fun Given2CommandsExpectWriteIndexInHeaderIncrease() {
+ val input1 = byteArrayOf(66)
+ val input2 = byteArrayOf(99)
+
+ val expect1 = byteArrayOf(5, 66, 0, 0, -25, 0)
+ val expect2 = byteArrayOf(5, 99, 1, 0, 64, 0)
+
+ val cmdPackets = WriteCommandPackets(input1)
+
+ val output1 = cmdPackets.getNextPacket()
+
+ cmdPackets.setData(input2)
+
+ val output2 = cmdPackets.getNextPacket()
+
+ assertEquals(expect1.contentToString(), output1.contentToString())
+ assertEquals(expect2.contentToString(), output2.contentToString())
+ }
+
+ @Test
+ fun GivenWriteIndexOverflowExpectWriteIndex1() {
+ val input1 = byteArrayOf(55)
+ val input2 = byteArrayOf(66)
+ val input3 = byteArrayOf(99)
+
+ val expect1 = byteArrayOf(5, 55, -2, 0, -19, 0)
+ val expect2 = byteArrayOf(5, 66, -1, 0, 86, 0)
+ val expect3 = byteArrayOf(5, 99, 1, 0, 64, 0)
+
+ val cmdPackets = WriteCommandPackets(byteArrayOf(0.toByte()))
+
+ // All this stuff to set the private field ^^
+ val writeCommandIndex = WriteCommandPackets::class.java.getDeclaredField("writeCommandIndex")
+ writeCommandIndex.isAccessible = true
+ writeCommandIndex.setInt(cmdPackets, 254)
+
+ cmdPackets.setData(input1)
+ val output1 = cmdPackets.getNextPacket()
+
+ cmdPackets.setData(input2)
+ val output2 = cmdPackets.getNextPacket()
+
+ cmdPackets.setData(input3)
+ val output3 = cmdPackets.getNextPacket()
+
+ assertEquals(expect1.contentToString(), output1.contentToString())
+ assertEquals(expect2.contentToString(), output2.contentToString())
+ assertEquals(expect3.contentToString(), output3.contentToString())
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/encryption/CryptTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/encryption/CryptTest.kt
new file mode 100644
index 0000000000..213bcdddbe
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/encryption/CryptTest.kt
@@ -0,0 +1,27 @@
+package info.nightscout.pump.medtrum.encryption
+
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class CryptTest {
+
+ @Test
+ fun GivenSNExpectKey() {
+ val crypt = Crypt()
+
+ val input: Long = 2859923929
+ val expect: Long = 3364239851
+ val output: Long = crypt.keyGen(input)
+ assertEquals(expect, output)
+ }
+
+ @Test
+ fun GivenSNExpectReal() {
+ val crypt = Crypt()
+
+ val input: Long = 2859923929
+ val expect: Long = 126009121
+ val output: Long = crypt.simpleDecrypt(input)
+ assertEquals(expect, output)
+ }
+}
From baa4376f688fc523162c316b1a025a70bd17df69 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 21 Feb 2023 10:59:31 +0100
Subject: [PATCH 004/116] Added MedtrumService
---
.../activities/MyPreferenceFragment.kt | 6 +-
.../nightscout/androidaps/di/AppComponent.kt | 4 +-
.../androidaps/di/PluginsListModule.kt | 4 +-
pump/medtrum/src/main/AndroidManifest.xml | 15 +-
...{MedtrumPumpPlugin.kt => MedtrumPlugin.kt} | 82 +++-
.../pump/medtrum/comm/ManufacturerData.kt | 8 +-
...mpModule.kt => MedtrumActivitiesModule.kt} | 3 +-
.../pump/medtrum/di/MedtrumModule.kt | 9 +
.../pump/medtrum/di/MedtrumServicesModule.kt | 11 +
.../pump/medtrum/services/BLEComm.kt | 352 ++++++++++--------
.../pump/medtrum/services/MedtrumService.kt | 201 ++++++++++
.../pump/medtrum/ui/MedtrumPumpFragment.kt | 8 +-
12 files changed, 503 insertions(+), 200 deletions(-)
rename pump/medtrum/src/main/java/info/nightscout/pump/medtrum/{MedtrumPumpPlugin.kt => MedtrumPlugin.kt} (67%)
rename pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/{MedtrumPumpModule.kt => MedtrumActivitiesModule.kt} (84%)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumServicesModule.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
index 0fcd7aa767..fc568738ea 100644
--- a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
@@ -54,7 +54,7 @@ import info.nightscout.plugins.sync.xdrip.XdripPlugin
import info.nightscout.pump.combo.ComboPlugin
import info.nightscout.pump.combov2.ComboV2Plugin
import info.nightscout.pump.diaconn.DiaconnG8Plugin
-import info.nightscout.pump.medtrum.MedtrumPumpPlugin
+import info.nightscout.pump.medtrum.MedtrumPlugin
import info.nightscout.pump.virtual.VirtualPumpPlugin
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventPreferenceChange
@@ -123,7 +123,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
@Inject lateinit var wearPlugin: WearPlugin
@Inject lateinit var maintenancePlugin: MaintenancePlugin
@Inject lateinit var eopatchPumpPlugin: EopatchPumpPlugin
- @Inject lateinit var medtrumPumpPlugin: MedtrumPumpPlugin
+ @Inject lateinit var MedtrumPlugin: MedtrumPlugin
@Inject lateinit var passwordCheck: PasswordCheck
@Inject lateinit var nsSettingStatus: NSSettingsStatus
@@ -214,7 +214,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(diaconnG8Plugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(eopatchPumpPlugin, rootKey, config.PUMPDRIVERS)
- addPreferencesFromResourceIfEnabled(medtrumPumpPlugin, rootKey, config.PUMPDRIVERS)
+ addPreferencesFromResourceIfEnabled(MedtrumPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
diff --git a/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt b/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt
index 4afc89af2d..f96fd72374 100644
--- a/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt
+++ b/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt
@@ -31,9 +31,9 @@ import info.nightscout.pump.common.di.PumpCommonModule
import info.nightscout.pump.dana.di.DanaHistoryModule
import info.nightscout.pump.dana.di.DanaModule
import info.nightscout.pump.danars.di.DanaRSModule
+import info.nightscout.pump.medtrum.di.MedtrumModule
import info.nightscout.pump.diaconn.di.DiaconnG8Module
import info.nightscout.pump.virtual.di.VirtualPumpModule
-import info.nightscout.pump.medtrum.di.MedtrumPumpModule
import info.nightscout.rx.di.RxModule
import info.nightscout.shared.di.SharedModule
import info.nightscout.shared.impl.di.SharedImplModule
@@ -88,7 +88,7 @@ import javax.inject.Singleton
OmnipodErosModule::class,
PumpCommonModule::class,
RileyLinkModule::class,
- MedtrumPumpModule::class,
+ MedtrumModule::class,
VirtualPumpModule::class
]
)
diff --git a/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt b/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt
index 9dd3ea48b1..4753c24877 100644
--- a/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt
+++ b/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt
@@ -46,7 +46,7 @@ import info.nightscout.plugins.sync.tidepool.TidepoolPlugin
import info.nightscout.plugins.sync.xdrip.XdripPlugin
import info.nightscout.pump.combo.ComboPlugin
import info.nightscout.pump.combov2.ComboV2Plugin
-import info.nightscout.pump.medtrum.MedtrumPumpPlugin
+import info.nightscout.pump.medtrum.MedtrumPlugin
import info.nightscout.pump.diaconn.DiaconnG8Plugin
import info.nightscout.pump.virtual.VirtualPumpPlugin
import info.nightscout.sensitivity.SensitivityAAPSPlugin
@@ -214,7 +214,7 @@ abstract class PluginsListModule {
@PumpDriver
@IntoMap
@IntKey(160)
- abstract fun bindMedtrumPumpPlugin(plugin: MedtrumPumpPlugin): PluginBase
+ abstract fun bindMedtrumPlugin(plugin: MedtrumPlugin): PluginBase
@Binds
@AllConfigs
diff --git a/pump/medtrum/src/main/AndroidManifest.xml b/pump/medtrum/src/main/AndroidManifest.xml
index 0a0938ae37..f589b49319 100644
--- a/pump/medtrum/src/main/AndroidManifest.xml
+++ b/pump/medtrum/src/main/AndroidManifest.xml
@@ -1,3 +1,16 @@
+
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
similarity index 67%
rename from pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
rename to pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 8cd141e446..60304f456d 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPumpPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -1,6 +1,12 @@
package info.nightscout.pump.medtrum
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.IBinder
import dagger.android.HasAndroidInjector
+import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@@ -21,33 +27,38 @@ import info.nightscout.interfaces.queue.CustomCommand
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.TimeChangeType
import info.nightscout.pump.medtrum.ui.MedtrumPumpFragment
+import info.nightscout.pump.medtrum.services.MedtrumService
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
+import info.nightscout.rx.events.EventAppExit
import info.nightscout.rx.events.EventAppInitialized
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
+import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.functions.Consumer
+import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.subjects.BehaviorSubject
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
-
@Singleton
-class MedtrumPumpPlugin @Inject constructor(
+class MedtrumPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
rh: ResourceHelper,
commandQueue: CommandQueue,
+ private val sp: SP,
private val aapsSchedulers: AapsSchedulers,
private val rxBus: RxBus,
+ private val context: Context,
private val fabricPrivacy: FabricPrivacy,
private val dateUtil: DateUtil,
private val pumpSync: PumpSync,
@@ -55,7 +66,7 @@ class MedtrumPumpPlugin @Inject constructor(
private val profileFunction: ProfileFunction
) : PumpPluginBase(
PluginDescription()
- .mainType(PluginType.PUMP) // TODO Prefs etc
+ .mainType(PluginType.PUMP)
.fragmentClass(MedtrumPumpFragment::class.java.name)
.pluginIcon(info.nightscout.core.ui.R.drawable.ic_eopatch2_128) // TODO
.pluginName(R.string.medtrum)
@@ -64,16 +75,51 @@ class MedtrumPumpPlugin @Inject constructor(
.description(R.string.medtrum_pump_description), injector, aapsLogger, rh, commandQueue
), Pump {
+ private val disposable = CompositeDisposable()
+ private var medtrumService: MedtrumService? = null
private var mPumpType: PumpType = PumpType.MEDTRUM_NANO
private val mPumpDescription = PumpDescription(mPumpType)
+ private var mDeviceSN: Long = 0
override fun onStart() {
super.onStart()
+ aapsLogger.debug(LTag.PUMP, "MedtrumPlugin onStart()")
+ val intent = Intent(context, MedtrumService::class.java)
+ context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
+ disposable += rxBus
+ .toObservable(EventAppExit::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ context.unbindService(mConnection) }, fabricPrivacy::logException)
+ changePump()
}
override fun onStop() {
+ aapsLogger.debug(LTag.PUMP, "MedtrumPlugin onStop()")
+ context.unbindService(mConnection)
+ disposable.clear()
super.onStop()
- aapsLogger.debug(LTag.PUMP, "MedtrumPumpPlugin onStop()")
+ }
+
+ private val mConnection: ServiceConnection = object : ServiceConnection {
+ override fun onServiceDisconnected(name: ComponentName) {
+ aapsLogger.debug(LTag.PUMP, "Service is disconnected")
+ medtrumService = null
+ }
+
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ aapsLogger.debug(LTag.PUMP, "Service is connected")
+ val mLocalBinder = service as MedtrumService.LocalBinder
+ medtrumService = mLocalBinder.serviceInstance
+ }
+ }
+
+ fun changePump() { // TODO: Call this on inputfield change?
+ try {
+ mDeviceSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
+ commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.device_changed), null)
+ } catch (e: NumberFormatException) {
+ aapsLogger.debug(LTag.PUMP, "changePump: invalid input!")
+ }
}
override fun isInitialized(): Boolean {
@@ -88,33 +134,35 @@ class MedtrumPumpPlugin @Inject constructor(
return false
}
- override fun isConnected(): Boolean {
- return false
- }
-
- override fun isConnecting(): Boolean {
- return false
- }
-
- override fun isHandshakeInProgress(): Boolean {
- return false
- }
+ override fun isConnected(): Boolean = medtrumService?.isConnected ?: false
+ override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false
+ override fun isHandshakeInProgress(): Boolean = false
override fun finishHandshaking() {
}
override fun connect(reason: String) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
+ aapsLogger.debug(LTag.PUMP, "Medtrum connect - service::$medtrumService")
+ aapsLogger.debug(LTag.PUMP, "Medtrum connect - mDeviceSN:$mDeviceSN")
+ if (medtrumService != null && mDeviceSN != 0.toLong()) {
+ aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
+ val success = medtrumService?.connect(reason, mDeviceSN) ?: false
+ if (!success) ToastUtils.errorToast(context, info.nightscout.core.ui.R.string.ble_not_supported_or_not_paired)
+ }
}
override fun disconnect(reason: String) {
- aapsLogger.debug(LTag.PUMP, "Medtrum disconnect - reason:$reason")
+ aapsLogger.debug(LTag.PUMP, "RS disconnect from: $reason")
+ medtrumService?.disconnect(reason)
}
override fun stopConnecting() {
+ medtrumService?.stopConnecting()
}
override fun getPumpStatus(reason: String) {
+ // TODO
}
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
@@ -177,7 +225,7 @@ class MedtrumPumpPlugin @Inject constructor(
}
override fun model(): PumpType {
- return mPumpType
+ return mPumpType
}
override fun serialNumber(): String {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ManufacturerData.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ManufacturerData.kt
index d567feb1ba..098d31d984 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ManufacturerData.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ManufacturerData.kt
@@ -14,15 +14,15 @@ class ManufacturerData(private val manufacturerDataBytes: ByteArray) {
fun setData(inputData: ByteArray) {
var index = 0
- val deviceIDBytes: ByteArray = manufacturerDataBytes.copyOfRange(index, index + 4)
+ val deviceIDBytes: ByteArray = inputData.copyOfRange(index, index + 4)
deviceID = deviceIDBytes.toLong()
index += 4
- deviceType = (manufacturerDataBytes[index] and 0xff.toByte()).toInt()
+ deviceType = (inputData[index] and 0xff.toByte()).toInt()
index += 1
- version = (manufacturerDataBytes[index] and 0xff.toByte()).toInt()
+ version = (inputData[index] and 0xff.toByte()).toInt()
}
- fun getDeviceID(): Long{
+ fun getDeviceSN(): Long{
return deviceID
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumActivitiesModule.kt
similarity index 84%
rename from pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt
rename to pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumActivitiesModule.kt
index 9589839625..8bac156f22 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumPumpModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumActivitiesModule.kt
@@ -1,13 +1,12 @@
package info.nightscout.pump.medtrum.di
-import dagger.Binds
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.pump.medtrum.ui.MedtrumPumpFragment
@Module
@Suppress("unused")
-abstract class MedtrumPumpModule {
+abstract class MedtrumActivitiesModule {
@ContributesAndroidInjector abstract fun contributesMedtrumPumpFragment(): MedtrumPumpFragment
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
new file mode 100644
index 0000000000..612053b6ec
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
@@ -0,0 +1,9 @@
+package info.nightscout.pump.medtrum.di
+
+import dagger.Module
+
+@Module(includes = [
+ MedtrumActivitiesModule::class,
+ MedtrumServicesModule::class
+])
+open class MedtrumModule
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumServicesModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumServicesModule.kt
new file mode 100644
index 0000000000..0c587bacc2
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumServicesModule.kt
@@ -0,0 +1,11 @@
+package info.nightscout.pump.medtrum.di
+
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import info.nightscout.pump.medtrum.services.MedtrumService
+
+@Module
+@Suppress("unused")
+abstract class MedtrumServicesModule {
+ @ContributesAndroidInjector abstract fun contributesDanaRSService(): MedtrumService
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 700bc49266..30fe7c2536 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -79,7 +79,7 @@ class BLEComm @Inject internal constructor(
var isConnecting = false
private var uartWrite: BluetoothGattCharacteristic? = null
- private var deviceID: Long = 0
+ private var mDeviceSN: Long = 0
/** Connect flow: 1. Start scanning for our device (SN entered in settings) */
@SuppressLint("MissingPermission")
@@ -98,7 +98,6 @@ class BLEComm @Inject internal constructor(
.build()
val filters = mutableListOf()
- if (deviceID == 0.toLong()) deviceID = rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput).toLong(radix = 16)
isConnected = false
// TODO: Maybe replace this by (or add) a isScanning parameter?
@@ -119,17 +118,43 @@ class BLEComm @Inject internal constructor(
mBluetoothAdapter?.bluetoothLeScanner?.stopScan(mScanCallback)
}
+ fun connect(from: String, deviceSN: Long): Boolean {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
+ ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED
+ ) {
+ ToastUtils.errorToast(context, context.getString(info.nightscout.core.ui.R.string.need_connect_permission))
+ aapsLogger.error(LTag.PUMPBTCOMM, "missing permission: $from")
+ return false
+ }
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Initializing BLEComm.")
+ if (mBluetoothAdapter == null) {
+ aapsLogger.error("Unable to obtain a BluetoothAdapter.")
+ return false
+ }
+ mDeviceSN = deviceSN
+ isConnecting = true
+ startScan()
+ return true
+ }
+
/** Connect flow: 2. When device is found this is called by onScanResult() */
@SuppressLint("MissingPermission")
@Synchronized
- fun connect(device: BluetoothDevice) {
+ fun connectGatt(device: BluetoothDevice) {
mBluetoothGatt =
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
}
@SuppressLint("MissingPermission")
@Synchronized
- fun disconnect() {
+ fun disconnect(from: String) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
+ ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED
+ ) {
+ aapsLogger.error(LTag.PUMPBTCOMM, "missing permission: $from")
+ return
+ }
+ aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
mBluetoothGatt?.disconnect()
mBluetoothGatt = null
}
@@ -156,11 +181,12 @@ class BLEComm @Inject internal constructor(
result.scanRecord?.getManufacturerSpecificData(MANUFACTURER_ID)
?.let { ManufacturerData(it) }
- aapsLogger.debug(LTag.PUMPBTCOMM, "Found DeviceID: " + manufacturerData?.getDeviceID())
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Found deviceSN: " + manufacturerData?.getDeviceSN())
- if (manufacturerData?.getDeviceID() == deviceID) {
+ if (manufacturerData?.getDeviceSN() == mDeviceSN) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Found our device! deviceSN: " + manufacturerData.getDeviceSN())
stopScan()
- connect(result.device)
+ connectGatt(result.device)
}
}
@@ -230,170 +256,166 @@ class BLEComm @Inject internal constructor(
checkDescriptor(descriptor)
}
}
+ }
- @SuppressLint("MissingPermission")
- @Synchronized
- private fun readDescriptor(descriptor: BluetoothGattDescriptor?) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "readDescriptor")
- if (mBluetoothAdapter == null || mBluetoothGatt == null || descriptor == null) {
- aapsLogger.error("BluetoothAdapter not initialized_ERROR")
- isConnecting = false
- isConnected = false
- return
- }
- mBluetoothGatt?.readDescriptor(descriptor)
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun readDescriptor(descriptor: BluetoothGattDescriptor?) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "readDescriptor")
+ if (mBluetoothAdapter == null || mBluetoothGatt == null || descriptor == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return
}
+ mBluetoothGatt?.readDescriptor(descriptor)
+ }
- private fun checkDescriptor(descriptor: BluetoothGattDescriptor) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "checkDescriptor")
- val service = getGattService()
- if (mBluetoothAdapter == null || mBluetoothGatt == null || service == null) {
- aapsLogger.error("BluetoothAdapter not initialized_ERROR")
- isConnecting = false
- isConnected = false
- return
- }
- if (descriptor.value.toInt() > 0) {
- var notificationEnabled = true
- val characteristics = service.characteristics
- for (j in 0 until characteristics.size) {
- val configDescriptor =
- characteristics[j].getDescriptor(UUID.fromString(CHARACTERISTIC_CONFIG_UUID))
- if (configDescriptor.value == null || configDescriptor.value.toInt() <= 0) {
- notificationEnabled = false
- }
- }
- if (notificationEnabled) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "Notifications enabled!")
- authorize()
+ @Suppress("DEPRECATION")
+ private fun checkDescriptor(descriptor: BluetoothGattDescriptor) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "checkDescriptor")
+ val service = getGattService()
+ if (mBluetoothAdapter == null || mBluetoothGatt == null || service == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return
+ }
+ if (descriptor.value.toInt() > 0) {
+ var notificationEnabled = true
+ val characteristics = service.characteristics
+ for (j in 0 until characteristics.size) {
+ val configDescriptor =
+ characteristics[j].getDescriptor(UUID.fromString(CHARACTERISTIC_CONFIG_UUID))
+ if (configDescriptor.value == null || configDescriptor.value.toInt() <= 0) {
+ notificationEnabled = false
}
}
- }
-
- @Suppress("DEPRECATION")
- @SuppressLint("MissingPermission")
- @Synchronized
- private fun setCharacteristicNotification(characteristic: BluetoothGattCharacteristic?, enabled: Boolean) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "setCharacteristicNotification")
- if (mBluetoothAdapter == null || mBluetoothGatt == null) {
- aapsLogger.error("BluetoothAdapter not initialized_ERROR")
- isConnecting = false
- isConnected = false
- return
- }
- mBluetoothGatt?.setCharacteristicNotification(characteristic, enabled)
- characteristic?.getDescriptor(UUID.fromString(CHARACTERISTIC_CONFIG_UUID))?.let {
- if (characteristic.properties and 0x10 > 0) {
- it.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
- mBluetoothGatt?.writeDescriptor(it)
- } else if (characteristic.properties and 0x20 > 0) {
- it.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
- mBluetoothGatt?.writeDescriptor(it)
- } else {
-
- }
- }
- }
-
- /** Connect flow: 3. When we are connected discover services*/
- @SuppressLint("MissingPermission")
- @Synchronized
- private fun onConnectionStateChangeSynchronized(gatt: BluetoothGatt, status: Int, newState: Int) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange newState: " + newState + " status: " + status)
- if (newState == BluetoothProfile.STATE_CONNECTED) {
- gatt.discoverServices()
- } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
- close()
- isConnected = false
- isConnecting = false
- rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
- aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
- disconnect()
- startScan()
- }
- }
-
- private fun readDataParsing(receivedData: ByteArray) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "<<>> " + Arrays.toString(receivedData))
- // TODO
- /** Connect flow: 6. Authorized */ // TODO place this at the correct place
- }
-
- private fun authorize() {
- aapsLogger.debug(LTag.PUMPBTCOMM, "Start auth!")
- val role = 2 // Fixed to 2 for pump
- val key = mCrypt.keyGen(deviceID)
- val commandData = byteArrayOf(COMMAND_AUTH_REQ) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4)
- sendMessage(commandData)
- }
-
- @Suppress("DEPRECATION")
- @SuppressLint("MissingPermission")
- @Synchronized
- private fun sendMessage(message: ByteArray) {
- // TODO: Handle packages which consist of multiple, Create a queue of packages
- aapsLogger.debug(LTag.PUMPBTCOMM, "sendMessage message = " + Arrays.toString(message))
- val writePacket = WriteCommandPackets(message)
- val value: ByteArray? = writePacket.getNextPacket()
-
- // TODO: queue
- writeCharacteristic(uartWriteBTGattChar, value)
- }
-
- private fun getGattService(): BluetoothGattService? {
- aapsLogger.debug(LTag.PUMPBTCOMM, "getGattService")
- if (mBluetoothAdapter == null || mBluetoothGatt == null) {
- aapsLogger.error("BluetoothAdapter not initialized_ERROR")
- isConnecting = false
- isConnected = false
- return null
- }
- return mBluetoothGatt?.getService(UUID.fromString(SERVICE_UUID))
- }
-
- private fun getGattCharacteristic(uuid: UUID): BluetoothGattCharacteristic? {
- aapsLogger.debug(LTag.PUMPBTCOMM, "getGattCharacteristic $uuid")
- val service = getGattService()
- if (mBluetoothAdapter == null || mBluetoothGatt == null || service == null) {
- aapsLogger.error("BluetoothAdapter not initialized_ERROR")
- isConnecting = false
- isConnected = false
- return null
- }
- return service.getCharacteristic(uuid)
- }
-
- @Suppress("DEPRECATION")
- @SuppressLint("MissingPermission")
- @Synchronized
- private fun writeCharacteristic(characteristic: BluetoothGattCharacteristic, data: ByteArray?) {
- Thread(Runnable {
- SystemClock.sleep(WRITE_DELAY_MILLIS)
- if (mBluetoothAdapter == null || mBluetoothGatt == null) {
- aapsLogger.error("BluetoothAdapter not initialized_ERROR")
- isConnecting = false
- isConnected = false
- return@Runnable
- }
- characteristic.value = data
- characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
- aapsLogger.debug("writeCharacteristic:" + Arrays.toString(data))
- mBluetoothGatt?.writeCharacteristic(characteristic)
- }).start()
- SystemClock.sleep(WRITE_DELAY_MILLIS)
- }
-
- private val uartWriteBTGattChar: BluetoothGattCharacteristic
- get() = uartWrite
- ?: BluetoothGattCharacteristic(UUID.fromString(WRITE_UUID), BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, 0).also { uartWrite = it }
-
- /** Connect flow: 4. When services are discovered find characteristics and set notifications*/
- private fun findCharacteristic() {
- val gattService = getGattService() ?: return
- val gattCharacteristics = gattService.characteristics
- for (gattCharacteristic in gattCharacteristics) {
- setCharacteristicNotification(gattCharacteristic, true)
+ if (notificationEnabled) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Notifications enabled!")
+ authorize()
}
}
}
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun setCharacteristicNotification(characteristic: BluetoothGattCharacteristic?, enabled: Boolean) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "setCharacteristicNotification")
+ if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return
+ }
+ mBluetoothGatt?.setCharacteristicNotification(characteristic, enabled)
+ characteristic?.getDescriptor(UUID.fromString(CHARACTERISTIC_CONFIG_UUID))?.let {
+ if (characteristic.properties and 0x10 > 0) {
+ it.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
+ mBluetoothGatt?.writeDescriptor(it)
+ } else if (characteristic.properties and 0x20 > 0) {
+ it.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
+ mBluetoothGatt?.writeDescriptor(it)
+ } else {
+
+ }
+ }
+ }
+
+ /** Connect flow: 3. When we are connected discover services*/
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun onConnectionStateChangeSynchronized(gatt: BluetoothGatt, status: Int, newState: Int) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange newState: " + newState + " status: " + status)
+ if (newState == BluetoothProfile.STATE_CONNECTED) {
+ gatt.discoverServices()
+ } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+ close()
+ isConnected = false
+ isConnecting = false
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
+ }
+ }
+
+ private fun readDataParsing(receivedData: ByteArray) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "<<>> " + Arrays.toString(receivedData))
+ // TODO
+ /** Connect flow: 6. Authorized */ // TODO place this at the correct place
+ }
+
+ private fun authorize() {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Start auth!")
+ val role = 2 // Fixed to 2 for pump
+ val key = mCrypt.keyGen(mDeviceSN)
+ val commandData = byteArrayOf(COMMAND_AUTH_REQ) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4)
+ sendMessage(commandData)
+ }
+
+ fun sendMessage(message: ByteArray) {
+ // TODO: Handle packages which consist of multiple, Create a queue of packages
+ aapsLogger.debug(LTag.PUMPBTCOMM, "sendMessage message = " + Arrays.toString(message))
+ val writePacket = WriteCommandPackets(message)
+ val value: ByteArray? = writePacket.getNextPacket()
+
+ // TODO: queue
+ writeCharacteristic(uartWriteBTGattChar, value)
+ }
+
+ private fun getGattService(): BluetoothGattService? {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "getGattService")
+ if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return null
+ }
+ return mBluetoothGatt?.getService(UUID.fromString(SERVICE_UUID))
+ }
+
+ private fun getGattCharacteristic(uuid: UUID): BluetoothGattCharacteristic? {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "getGattCharacteristic $uuid")
+ val service = getGattService()
+ if (mBluetoothAdapter == null || mBluetoothGatt == null || service == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return null
+ }
+ return service.getCharacteristic(uuid)
+ }
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("MissingPermission")
+ @Synchronized
+ private fun writeCharacteristic(characteristic: BluetoothGattCharacteristic, data: ByteArray?) {
+ Thread(Runnable {
+ SystemClock.sleep(WRITE_DELAY_MILLIS)
+ if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ return@Runnable
+ }
+ characteristic.value = data
+ characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
+ aapsLogger.debug("writeCharacteristic:" + Arrays.toString(data))
+ mBluetoothGatt?.writeCharacteristic(characteristic)
+ }).start()
+ SystemClock.sleep(WRITE_DELAY_MILLIS)
+ }
+
+ private val uartWriteBTGattChar: BluetoothGattCharacteristic
+ get() = uartWrite
+ ?: BluetoothGattCharacteristic(UUID.fromString(WRITE_UUID), BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, 0).also { uartWrite = it }
+
+ /** Connect flow: 4. When services are discovered find characteristics and set notifications*/
+ private fun findCharacteristic() {
+ val gattService = getGattService() ?: return
+ val gattCharacteristics = gattService.characteristics
+ for (gattCharacteristic in gattCharacteristics) {
+ setCharacteristicNotification(gattCharacteristic, true)
+ }
+ }
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
new file mode 100644
index 0000000000..6b45d59f38
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -0,0 +1,201 @@
+package info.nightscout.pump.medtrum.services
+
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+import android.os.SystemClock
+import dagger.android.DaggerService
+import dagger.android.HasAndroidInjector
+import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.interfaces.Constants
+import info.nightscout.interfaces.constraints.Constraints
+import info.nightscout.interfaces.notifications.Notification
+import info.nightscout.interfaces.plugin.ActivePlugin
+import info.nightscout.interfaces.profile.Profile
+import info.nightscout.interfaces.profile.ProfileFunction
+import info.nightscout.interfaces.pump.BolusProgressData
+import info.nightscout.interfaces.pump.PumpEnactResult
+import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.queue.Callback
+import info.nightscout.interfaces.queue.Command
+import info.nightscout.interfaces.queue.CommandQueue
+import info.nightscout.interfaces.ui.UiInteraction
+import info.nightscout.pump.medtrum.MedtrumPlugin
+import info.nightscout.rx.AapsSchedulers
+import info.nightscout.rx.bus.RxBus
+import info.nightscout.rx.events.EventAppExit
+import info.nightscout.rx.events.EventInitializationChanged
+import info.nightscout.rx.events.EventOverviewBolusProgress
+import info.nightscout.rx.events.EventProfileSwitchChanged
+import info.nightscout.rx.events.EventPumpStatusChanged
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.interfaces.ResourceHelper
+import info.nightscout.shared.sharedPreferences.SP
+import info.nightscout.shared.utils.DateUtil
+import info.nightscout.shared.utils.T
+import io.reactivex.rxjava3.disposables.CompositeDisposable
+import io.reactivex.rxjava3.kotlin.plusAssign
+import org.joda.time.DateTime
+import org.joda.time.DateTimeZone
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+import kotlin.math.abs
+import kotlin.math.min
+
+class MedtrumService : DaggerService() {
+
+ @Inject lateinit var injector: HasAndroidInjector
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var rxBus: RxBus
+ @Inject lateinit var sp: SP
+ @Inject lateinit var rh: ResourceHelper
+ @Inject lateinit var profileFunction: ProfileFunction
+ @Inject lateinit var commandQueue: CommandQueue
+ @Inject lateinit var context: Context
+ @Inject lateinit var medtrumPlugin: MedtrumPlugin
+ @Inject lateinit var activePlugin: ActivePlugin
+ @Inject lateinit var constraintChecker: Constraints
+ @Inject lateinit var uiInteraction: UiInteraction
+ @Inject lateinit var bleComm: BLEComm
+ @Inject lateinit var fabricPrivacy: FabricPrivacy
+ @Inject lateinit var pumpSync: PumpSync
+ @Inject lateinit var dateUtil: DateUtil
+
+ private val disposable = CompositeDisposable()
+ private val mBinder: IBinder = LocalBinder()
+
+ override fun onCreate() {
+ super.onCreate()
+ disposable += rxBus
+ .toObservable(EventAppExit::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ stopSelf() }, fabricPrivacy::logException)
+ }
+
+ override fun onDestroy() {
+ disposable.clear()
+ super.onDestroy()
+ }
+
+ val isConnected: Boolean
+ get() = bleComm.isConnected
+
+ val isConnecting: Boolean
+ get() = bleComm.isConnecting
+
+ fun connect(from: String, deviceSN: Long): Boolean {
+ // TODO Check we might want to replace this with start scan?
+ return bleComm.connect(from, deviceSN)
+ }
+
+ fun stopConnecting() {
+ bleComm.stopConnecting()
+ }
+
+ fun disconnect(from: String) {
+ bleComm.disconnect(from)
+ }
+
+ fun sendMessage(message: ByteArray) { // TODO Check what we use here?
+ // TODO
+ bleComm.sendMessage(message)
+ }
+
+ fun readPumpStatus() {
+ // TODO
+ }
+
+ fun loadEvents(): PumpEnactResult {
+ if (!medtrumPlugin.isInitialized()) {
+ val result = PumpEnactResult(injector).success(false)
+ result.comment = "pump not initialized"
+ return result
+ }
+ // TODO need this? Check
+ val result = PumpEnactResult(injector)
+ return result
+ }
+
+ fun setUserSettings(): PumpEnactResult {
+ // TODO need this? Check
+ val result = PumpEnactResult(injector)
+ return result
+ }
+
+ fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean {
+ if (!isConnected) return false
+ // TODO
+ return false
+ }
+
+ fun bolusStop() {
+ // TODO
+ }
+
+ fun tempBasal(percent: Int, durationInHours: Int): Boolean {
+ // TODO
+ return false
+ }
+
+ fun highTempBasal(percent: Int): Boolean {
+ // TODO
+ return false
+ }
+
+ fun tempBasalShortDuration(percent: Int, durationInMinutes: Int): Boolean {
+ if (durationInMinutes != 15 && durationInMinutes != 30) {
+ aapsLogger.error(LTag.PUMPCOMM, "Wrong duration param")
+ return false
+ }
+ // TODO
+ return false
+ }
+
+ fun tempBasalStop(): Boolean {
+ if (!isConnected) return false
+ // TODO
+ return false
+ }
+
+ fun extendedBolus(insulin: Double, durationInHalfHours: Int): Boolean {
+ if (!isConnected) return false
+ // TODO
+ return false
+ }
+
+ fun extendedBolusStop(): Boolean {
+ if (!isConnected) return false
+ // TODO
+ return false
+ }
+
+ fun updateBasalsInPump(profile: Profile): Boolean {
+ if (!isConnected) return false
+ // TODO
+ return false
+ }
+
+ fun loadHistory(type: Byte): PumpEnactResult {
+ val result = PumpEnactResult(injector)
+ if (!isConnected) return result
+ // TODO
+ return result
+ }
+
+ inner class LocalBinder : Binder() {
+ val serviceInstance: MedtrumService
+ get() = this@MedtrumService
+ }
+
+ override fun onBind(intent: Intent): IBinder {
+ return mBinder
+ }
+
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ return Service.START_STICKY
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt
index 8d3297c56c..ac94004d8b 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt
@@ -13,7 +13,7 @@ import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.pump.medtrum.databinding.MedtrumPumpFragmentBinding
import info.nightscout.pump.medtrum.events.EventMedtrumPumpUpdateGui
-import info.nightscout.pump.medtrum.MedtrumPumpPlugin
+import info.nightscout.pump.medtrum.MedtrumPlugin
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventExtendedBolusChange
@@ -31,7 +31,7 @@ class MedtrumPumpFragment : DaggerFragment() {
@Inject lateinit var rh: ResourceHelper
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var fabricPrivacy: FabricPrivacy
- @Inject lateinit var medtrumPumpPlugin: MedtrumPumpPlugin
+ @Inject lateinit var MedtrumPlugin: MedtrumPlugin
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var aapsSchedulers: AapsSchedulers
@@ -90,7 +90,7 @@ class MedtrumPumpFragment : DaggerFragment() {
private fun updateGui() {
if (_binding == null) return
val profile = profileFunction.getProfile() ?: return
- binding.baseBasalRate.text = rh.gs(info.nightscout.core.ui.R.string.pump_base_basal_rate, medtrumPumpPlugin.baseBasalRate)
+ binding.baseBasalRate.text = rh.gs(info.nightscout.core.ui.R.string.pump_base_basal_rate, MedtrumPlugin.baseBasalRate)
binding.tempbasal.text = iobCobCalculator.getTempBasal(dateUtil.now())?.toStringFull(profile, dateUtil)
?: ""
binding.extendedbolus.text = iobCobCalculator.getExtendedBolus(dateUtil.now())?.toStringFull(dateUtil)
@@ -98,6 +98,6 @@ class MedtrumPumpFragment : DaggerFragment() {
binding.battery.text = rh.gs(info.nightscout.core.ui.R.string.format_percent, 0) // TODO
binding.reservoir.text = rh.gs(info.nightscout.interfaces.R.string.format_insulin_units, 0.0) // TODO
- binding.serialNumber.text = medtrumPumpPlugin.serialNumber()
+ binding.serialNumber.text = MedtrumPlugin.serialNumber()
}
}
From f31f6c1649b2123f5b79b7a416be5acf2c6dd8d7 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 23 Feb 2023 15:41:12 +0100
Subject: [PATCH 005/116] Proper handling of setCharacteristicNotification
---
app/build.gradle | 2 +-
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 21 ++-
.../pump/medtrum/comm/WriteCommandPackets.kt | 43 +++---
.../pump/medtrum/encryption/Crypt.kt | 13 +-
.../pump/medtrum/services/BLEComm.kt | 128 +++++++++++-------
.../pump/medtrum/services/MedtrumService.kt | 8 +-
.../medtrum/comm/WriteCommandPacketsTest.kt | 20 +--
7 files changed, 132 insertions(+), 103 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 16c2b9c158..b3efbe17e6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -111,7 +111,7 @@ android {
defaultConfig {
multiDexEnabled true
versionCode 1500
- version "3.2.0-dev-i"
+ version "3.2.0-dev-i-medtrum"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 60304f456d..f799d15e51 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -90,6 +90,15 @@ class MedtrumPlugin @Inject constructor(
.toObservable(EventAppExit::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ context.unbindService(mConnection) }, fabricPrivacy::logException)
+ disposable += rxBus
+ .toObservable(EventPreferenceChange::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event ->
+ if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput))) {
+ pumpSync.connectNewPump()
+ changePump()
+ }
+ }, fabricPrivacy::logException)
changePump()
}
@@ -113,13 +122,15 @@ class MedtrumPlugin @Inject constructor(
}
}
- fun changePump() { // TODO: Call this on inputfield change?
+ fun changePump() {
+ aapsLogger.debug(LTag.PUMP, "changePump: called!")
try {
mDeviceSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
- commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.device_changed), null)
} catch (e: NumberFormatException) {
- aapsLogger.debug(LTag.PUMP, "changePump: invalid input!")
+ aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
}
+ // TODO: add medtrumPump.reset()
+ commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.device_changed), null)
}
override fun isInitialized(): Boolean {
@@ -148,7 +159,7 @@ class MedtrumPlugin @Inject constructor(
if (medtrumService != null && mDeviceSN != 0.toLong()) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
val success = medtrumService?.connect(reason, mDeviceSN) ?: false
- if (!success) ToastUtils.errorToast(context, info.nightscout.core.ui.R.string.ble_not_supported_or_not_paired)
+ if (!success) ToastUtils.errorToast(context, info.nightscout.core.ui.R.string.ble_not_supported_or_not_paired)
}
}
@@ -162,7 +173,7 @@ class MedtrumPlugin @Inject constructor(
}
override fun getPumpStatus(reason: String) {
- // TODO
+ medtrumService?.readPumpStatus()
}
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
index 517072f8d6..7a80cab3c3 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
@@ -3,19 +3,13 @@ package info.nightscout.pump.medtrum.comm
import info.nightscout.pump.medtrum.encryption.Crypt
-class WriteCommandPackets(private val command: ByteArray) {
+class WriteCommandPackets() {
- val crypt = Crypt()
+ private val CRC_8_TABLE: IntArray = intArrayOf(0, 155, 173, 54, 193, 90, 108, 247, 25, 130, 180, 47, 216, 67, 117, 238, 50, 169, 159, 4, 243, 104, 94, 197, 43, 176, 134, 29, 234, 113, 71, 220, 100, 255, 201, 82, 165, 62, 8, 147, 125, 230, 208, 75, 188, 39, 17, 138, 86, 205, 251, 96, 151, 12, 58, 161, 79, 212, 226, 121, 142, 21, 35, 184, 200, 83, 101, 254, 9, 146, 164, 63, 209, 74, 124, 231, 16, 139, 189, 38, 250, 97, 87, 204, 59, 160, 150, 13, 227, 120, 78, 213, 34, 185, 143, 20, 172, 55, 1, 154, 109, 246, 192, 91, 181, 46, 24, 131, 116, 239, 217, 66, 158, 5, 51, 168, 95, 196, 242, 105, 135, 28, 42, 177, 70, 221, 235, 112, 11, 144, 166, 61, 202, 81, 103, 252, 18, 137, 191, 36, 211, 72, 126, 229, 57, 162, 148, 15, 248, 99, 85, 206, 32, 187, 141, 22, 225, 122, 76, 215, 111, 244, 194, 89, 174, 53, 3, 152, 118, 237, 219, 64, 183, 44, 26, 129, 93, 198, 240, 107, 156, 7, 49, 170, 68, 223, 233, 114, 133, 30, 40, 179, 195, 88, 110, 245, 2, 153, 175, 52, 218, 65, 119, 236, 27, 128, 182, 45, 241, 106, 92, 199, 48, 171, 157, 6, 232, 115, 69, 222, 41, 178, 132, 31, 167, 60, 10, 145, 102, 253, 203, 80, 190, 37, 19, 136, 127, 228, 210, 73, 149, 14, 56, 163, 84, 207, 249, 98, 140, 23, 33, 186, 77, 214, 224, 123)
private val packages = mutableListOf()
private var index = 0
- private var writeCommandIndex = 0
- private var allPacketsConsumed = false
-
-
- init {
- setData(command)
- }
+ private var sequenceNumber = 0
fun setData(inputData: ByteArray) {
resetPackets()
@@ -24,12 +18,12 @@ class WriteCommandPackets(private val command: ByteArray) {
var header = byteArrayOf(
(inputData.size + 4).toByte(),
inputData[0],
- writeCommandIndex.toByte(),
+ sequenceNumber.toByte(),
pkgIndex.toByte()
)
var tmp: ByteArray = header + inputData.copyOfRange(1, inputData.size)
- var totalCommand: ByteArray = tmp + crypt.calcCrc8(tmp, tmp.size).toByte()
+ var totalCommand: ByteArray = tmp + calcCrc8(tmp, tmp.size).toByte()
if ((totalCommand.size - header.size) <= 15) {
packages.add(totalCommand + 0.toByte())
@@ -40,7 +34,7 @@ class WriteCommandPackets(private val command: ByteArray) {
while (remainingCommand.size > 15) {
header[3] = pkgIndex.toByte()
tmp = header + remainingCommand.copyOfRange(0, 15)
- packages.add(tmp + crypt.calcCrc8(tmp, tmp.size).toByte())
+ packages.add(tmp + calcCrc8(tmp, tmp.size).toByte())
remainingCommand = remainingCommand.copyOfRange(15, remainingCommand.size)
pkgIndex = (pkgIndex + 1) % 256
@@ -49,14 +43,9 @@ class WriteCommandPackets(private val command: ByteArray) {
// Add last package
header[3] = pkgIndex.toByte()
tmp = header + remainingCommand
- packages.add(tmp + crypt.calcCrc8(tmp, tmp.size).toByte())
+ packages.add(tmp + calcCrc8(tmp, tmp.size).toByte())
}
- writeCommandIndex = (writeCommandIndex % 255) + 1
- }
-
-
- fun allPacketsConsumed(): Boolean {
- return allPacketsConsumed
+ sequenceNumber = (sequenceNumber % 255) + 1
}
fun getNextPacket(): ByteArray? {
@@ -65,15 +54,23 @@ class WriteCommandPackets(private val command: ByteArray) {
ret = packages[index]
index++
}
- if (index >= packages.size) {
- allPacketsConsumed = true
- }
return ret
}
+ fun allPacketsConsumed(): Boolean {
+ return !(index < packages.size)
+ }
+
private fun resetPackets() {
packages.clear()
index = 0
- allPacketsConsumed = false
+ }
+
+ private fun calcCrc8(value: ByteArray, size: Int): Int {
+ var crc8 = 0
+ for (i in 0 until size) {
+ crc8 = CRC_8_TABLE[(value[i].toInt() and 255) xor (crc8 and 255)].toInt() and 255
+ }
+ return crc8
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
index 093c3a8c12..4cd3e182bc 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
@@ -4,9 +4,8 @@ import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toLong
class Crypt {
- val RIJNDEAL_S_BOX: IntArray = intArrayOf(99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22)
- val RIJNDEAL_INVERSE_S_BOX: IntArray = intArrayOf(82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125)
- val CRC_8_TABLE: IntArray = intArrayOf(0, 155, 173, 54, 193, 90, 108, 247, 25, 130, 180, 47, 216, 67, 117, 238, 50, 169, 159, 4, 243, 104, 94, 197, 43, 176, 134, 29, 234, 113, 71, 220, 100, 255, 201, 82, 165, 62, 8, 147, 125, 230, 208, 75, 188, 39, 17, 138, 86, 205, 251, 96, 151, 12, 58, 161, 79, 212, 226, 121, 142, 21, 35, 184, 200, 83, 101, 254, 9, 146, 164, 63, 209, 74, 124, 231, 16, 139, 189, 38, 250, 97, 87, 204, 59, 160, 150, 13, 227, 120, 78, 213, 34, 185, 143, 20, 172, 55, 1, 154, 109, 246, 192, 91, 181, 46, 24, 131, 116, 239, 217, 66, 158, 5, 51, 168, 95, 196, 242, 105, 135, 28, 42, 177, 70, 221, 235, 112, 11, 144, 166, 61, 202, 81, 103, 252, 18, 137, 191, 36, 211, 72, 126, 229, 57, 162, 148, 15, 248, 99, 85, 206, 32, 187, 141, 22, 225, 122, 76, 215, 111, 244, 194, 89, 174, 53, 3, 152, 118, 237, 219, 64, 183, 44, 26, 129, 93, 198, 240, 107, 156, 7, 49, 170, 68, 223, 233, 114, 133, 30, 40, 179, 195, 88, 110, 245, 2, 153, 175, 52, 218, 65, 119, 236, 27, 128, 182, 45, 241, 106, 92, 199, 48, 171, 157, 6, 232, 115, 69, 222, 41, 178, 132, 31, 167, 60, 10, 145, 102, 253, 203, 80, 190, 37, 19, 136, 127, 228, 210, 73, 149, 14, 56, 163, 84, 207, 249, 98, 140, 23, 33, 186, 77, 214, 224, 123)
+ private val RIJNDEAL_S_BOX: IntArray = intArrayOf(99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22)
+ private val RIJNDEAL_INVERSE_S_BOX: IntArray = intArrayOf(82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125)
val MED_CIPHER: Long = 1344751489
@@ -27,14 +26,6 @@ class Crypt {
return ret
}
- fun calcCrc8(value: ByteArray, size: Int): Int {
- var crc8 = 0
- for (i in 0 until size) {
- crc8 = CRC_8_TABLE[(value[i].toInt() and 255) xor (crc8 and 255)].toInt() and 255
- }
- return crc8
- }
-
private fun simpleCrypt(inputData: Long): Long {
var temp = inputData xor MED_CIPHER
for (i in 0 until 32) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 30fe7c2536..316466dbce 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -19,6 +19,8 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
+import android.os.Handler
+import android.os.HandlerThread
import android.os.SystemClock
import androidx.core.app.ActivityCompat
import dagger.android.HasAndroidInjector
@@ -64,13 +66,19 @@ class BLEComm @Inject internal constructor(
private const val WRITE_DELAY_MILLIS: Long = 50
private const val SERVICE_UUID = "669A9001-0008-968F-E311-6050405558B3"
private const val READ_UUID = "669a9120-0008-968f-e311-6050405558b3"
- private const val WRITE_UUID = "669a9101-0008-968f-e311-6050405558b"
- private const val CHARACTERISTIC_CONFIG_UUID = "00002902-0000-1000-8000-00805f9b34fb"
+ private const val WRITE_UUID = "669a9101-0008-968f-e311-6050405558b3"
+ private const val CONFIG_UUID = "00002902-0000-1000-8000-00805f9b34fb"
+
+ private const val NEEDS_ENABLE_NOTIFICATION = 0x10
+ private const val NEEDS_ENABLE_INDICATION = 0x20
+ private const val NEEDS_ENABLE = 0x30
private const val MANUFACTURER_ID = 18305
private const val COMMAND_AUTH_REQ: Byte = 5
}
+ private val handler =
+ Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val mBluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
private var mBluetoothGatt: BluetoothGatt? = null
private val mCrypt = Crypt()
@@ -78,9 +86,12 @@ class BLEComm @Inject internal constructor(
var isConnected = false
var isConnecting = false
private var uartWrite: BluetoothGattCharacteristic? = null
+ private var uartRead: BluetoothGattCharacteristic? = null
private var mDeviceSN: Long = 0
+ private var mWritePackets = WriteCommandPackets()
+
/** Connect flow: 1. Start scanning for our device (SN entered in settings) */
@SuppressLint("MissingPermission")
@Synchronized
@@ -210,30 +221,29 @@ class BLEComm @Inject internal constructor(
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicRead status = " + status)
- if (status == BluetoothGatt.GATT_SUCCESS) {
- readDataParsing(characteristic.value)
- }
}
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged")
+ // TODO: Make split between Notif and Indication
+ // Notif contains pump status and alarms
readDataParsing(characteristic.value)
}
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite status = " + status)
- // TODO (note also queue, note that in danars there is no response, so check where to handle multiple packets)
- // aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value))
- // Thread {
- // synchronized(mSendQueue) {
- // // after message sent, check if there is the rest of the message waiting and send it
- // if (mSendQueue.size > 0) {
- // val bytes = mSendQueue[0]
- // mSendQueue.removeAt(0)
- // writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
- // }
- // }
- // }.start()
+
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ // Check if we need to finish our command!
+ synchronized(mWritePackets) {
+ val value: ByteArray? = mWritePackets.getNextPacket()
+ if (value != null) {
+ writeCharacteristic(uartWriteBTGattChar, value)
+ }
+ }
+ } else {
+ // TODO: What to do here?
+ }
}
override fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) {
@@ -286,7 +296,7 @@ class BLEComm @Inject internal constructor(
val characteristics = service.characteristics
for (j in 0 until characteristics.size) {
val configDescriptor =
- characteristics[j].getDescriptor(UUID.fromString(CHARACTERISTIC_CONFIG_UUID))
+ characteristics[j].getDescriptor(UUID.fromString(CONFIG_UUID))
if (configDescriptor.value == null || configDescriptor.value.toInt() <= 0) {
notificationEnabled = false
}
@@ -310,11 +320,11 @@ class BLEComm @Inject internal constructor(
return
}
mBluetoothGatt?.setCharacteristicNotification(characteristic, enabled)
- characteristic?.getDescriptor(UUID.fromString(CHARACTERISTIC_CONFIG_UUID))?.let {
- if (characteristic.properties and 0x10 > 0) {
+ characteristic?.getDescriptor(UUID.fromString(CONFIG_UUID))?.let {
+ if (characteristic.properties and NEEDS_ENABLE_NOTIFICATION > 0) {
it.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
mBluetoothGatt?.writeDescriptor(it)
- } else if (characteristic.properties and 0x20 > 0) {
+ } else if (characteristic.properties and NEEDS_ENABLE_INDICATION > 0) {
it.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
mBluetoothGatt?.writeDescriptor(it)
} else {
@@ -329,7 +339,9 @@ class BLEComm @Inject internal constructor(
private fun onConnectionStateChangeSynchronized(gatt: BluetoothGatt, status: Int, newState: Int) {
aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange newState: " + newState + " status: " + status)
if (newState == BluetoothProfile.STATE_CONNECTED) {
- gatt.discoverServices()
+ handler.postDelayed({
+ mBluetoothGatt?.discoverServices()
+ }, WRITE_DELAY_MILLIS)
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
close()
isConnected = false
@@ -340,9 +352,12 @@ class BLEComm @Inject internal constructor(
}
private fun readDataParsing(receivedData: ByteArray) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "<<>> " + Arrays.toString(receivedData))
- // TODO
- /** Connect flow: 6. Authorized */ // TODO place this at the correct place
+ aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< readDataParsing " + Arrays.toString(receivedData))
+ // TODO Implement
+ // TODO place this at the correct place
+ /** Connect flow: 6. Authorized */
+ isConnected = true
+ isConnecting = false
}
private fun authorize() {
@@ -354,13 +369,20 @@ class BLEComm @Inject internal constructor(
}
fun sendMessage(message: ByteArray) {
- // TODO: Handle packages which consist of multiple, Create a queue of packages
aapsLogger.debug(LTag.PUMPBTCOMM, "sendMessage message = " + Arrays.toString(message))
- val writePacket = WriteCommandPackets(message)
- val value: ByteArray? = writePacket.getNextPacket()
-
- // TODO: queue
- writeCharacteristic(uartWriteBTGattChar, value)
+ if (!mWritePackets.allPacketsConsumed()) {
+ aapsLogger.error(LTag.PUMPBTCOMM, "sendMessage not all packets consumed!! unable to sent message!")
+ return
+ }
+ synchronized(mWritePackets) {
+ mWritePackets.setData(message)
+ val value: ByteArray? = mWritePackets.getNextPacket()
+ if (value != null) {
+ writeCharacteristic(uartWriteBTGattChar, value)
+ } else {
+ aapsLogger.error(LTag.PUMPBTCOMM, "sendMessage error in writePacket!")
+ }
+ }
}
private fun getGattService(): BluetoothGattService? {
@@ -390,20 +412,18 @@ class BLEComm @Inject internal constructor(
@SuppressLint("MissingPermission")
@Synchronized
private fun writeCharacteristic(characteristic: BluetoothGattCharacteristic, data: ByteArray?) {
- Thread(Runnable {
- SystemClock.sleep(WRITE_DELAY_MILLIS)
- if (mBluetoothAdapter == null || mBluetoothGatt == null) {
- aapsLogger.error("BluetoothAdapter not initialized_ERROR")
- isConnecting = false
- isConnected = false
- return@Runnable
- }
- characteristic.value = data
- characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
- aapsLogger.debug("writeCharacteristic:" + Arrays.toString(data))
- mBluetoothGatt?.writeCharacteristic(characteristic)
- }).start()
- SystemClock.sleep(WRITE_DELAY_MILLIS)
+ handler.postDelayed({
+ if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+ aapsLogger.error("BluetoothAdapter not initialized_ERROR")
+ isConnecting = false
+ isConnected = false
+ } else {
+ characteristic.value = data
+ characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
+ aapsLogger.debug(LTag.PUMPBTCOMM, "writeCharacteristic:" + Arrays.toString(data))
+ mBluetoothGatt?.writeCharacteristic(characteristic)
+ }
+ }, WRITE_DELAY_MILLIS)
}
private val uartWriteBTGattChar: BluetoothGattCharacteristic
@@ -413,9 +433,23 @@ class BLEComm @Inject internal constructor(
/** Connect flow: 4. When services are discovered find characteristics and set notifications*/
private fun findCharacteristic() {
val gattService = getGattService() ?: return
+ var uuid: String
val gattCharacteristics = gattService.characteristics
- for (gattCharacteristic in gattCharacteristics) {
- setCharacteristicNotification(gattCharacteristic, true)
+ for (i in 0..gattCharacteristics.size - 1) {
+ val gattCharacteristic = gattCharacteristics.get(i)
+ // Check whether read or write properties is set, the pump needs us to enable notifications on all characteristics that have these properties
+ if (gattCharacteristic.properties and NEEDS_ENABLE > 0) {
+ handler.postDelayed({
+ uuid = gattCharacteristic.uuid.toString()
+ setCharacteristicNotification(gattCharacteristic, true)
+ if (READ_UUID == uuid) {
+ uartRead = gattCharacteristic
+ }
+ if (WRITE_UUID == uuid) {
+ uartWrite = gattCharacteristic
+ }
+ }, (i * 600).toLong())
+ }
}
}
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 6b45d59f38..d4b8e2b674 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -179,13 +179,7 @@ class MedtrumService : DaggerService() {
return false
}
- fun loadHistory(type: Byte): PumpEnactResult {
- val result = PumpEnactResult(injector)
- if (!isConnected) return result
- // TODO
- return result
- }
-
+ /** Service stuff */
inner class LocalBinder : Binder() {
val serviceInstance: MedtrumService
get() = this@MedtrumService
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/WriteCommandPacketsTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/WriteCommandPacketsTest.kt
index 10d05c2ad6..a414540b97 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/WriteCommandPacketsTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/WriteCommandPacketsTest.kt
@@ -9,7 +9,8 @@ class WriteCommandPacketsTest {
fun Given14LongCommandExpectOnePacket() {
val input = byteArrayOf(5, 2, 0, 0, 0, 0, -21, 57, -122, -56)
val expect = byteArrayOf(14, 5, 0, 0, 2, 0, 0, 0, 0, -21, 57, -122, -56, -93, 0)
- val cmdPackets = WriteCommandPackets(input)
+ val cmdPackets = WriteCommandPackets()
+ cmdPackets.setData(input)
val output = cmdPackets.getNextPacket()
assertEquals(expect.contentToString(), output.contentToString())
@@ -22,7 +23,8 @@ class WriteCommandPacketsTest {
val expect2 = byteArrayOf(41, 18, 0, 2, 0, -96, 2, -16, 96, 2, 104, 33, 2, -32, -31, 1, -64, 3, 2, -3)
val expect3 = byteArrayOf(41, 18, 0, 3, -20, 36, 2, 100, -123, 2, -125, -89)
- val cmdPackets = WriteCommandPackets(input)
+ val cmdPackets = WriteCommandPackets()
+ cmdPackets.setData(input)
val output1 = cmdPackets.getNextPacket()
val output2 = cmdPackets.getNextPacket()
val output3 = cmdPackets.getNextPacket()
@@ -34,7 +36,6 @@ class WriteCommandPacketsTest {
assertEquals(expect3.contentToString(), output3.contentToString())
assertNull(output4)
assertEquals(true, cmdPackets.allPacketsConsumed())
-
}
@Test
@@ -45,7 +46,8 @@ class WriteCommandPacketsTest {
val expect1 = byteArrayOf(5, 66, 0, 0, -25, 0)
val expect2 = byteArrayOf(5, 99, 1, 0, 64, 0)
- val cmdPackets = WriteCommandPackets(input1)
+ val cmdPackets = WriteCommandPackets()
+ cmdPackets.setData(input1)
val output1 = cmdPackets.getNextPacket()
@@ -58,7 +60,7 @@ class WriteCommandPacketsTest {
}
@Test
- fun GivenWriteIndexOverflowExpectWriteIndex1() {
+ fun GivenSequenceNumberOverflowExpectSequenceNumber1() {
val input1 = byteArrayOf(55)
val input2 = byteArrayOf(66)
val input3 = byteArrayOf(99)
@@ -67,12 +69,12 @@ class WriteCommandPacketsTest {
val expect2 = byteArrayOf(5, 66, -1, 0, 86, 0)
val expect3 = byteArrayOf(5, 99, 1, 0, 64, 0)
- val cmdPackets = WriteCommandPackets(byteArrayOf(0.toByte()))
+ val cmdPackets = WriteCommandPackets()
// All this stuff to set the private field ^^
- val writeCommandIndex = WriteCommandPackets::class.java.getDeclaredField("writeCommandIndex")
- writeCommandIndex.isAccessible = true
- writeCommandIndex.setInt(cmdPackets, 254)
+ val sequenceNumber = WriteCommandPackets::class.java.getDeclaredField("sequenceNumber")
+ sequenceNumber.isAccessible = true
+ sequenceNumber.setInt(cmdPackets, 254)
cmdPackets.setData(input1)
val output1 = cmdPackets.getNextPacket()
From ed100a4eb05d0fef7c9c0e3a39b1a9fb4d5efbb2 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 23 Feb 2023 21:05:50 +0100
Subject: [PATCH 006/116] BLEComm: Added callbacks to enable handling of
notifications in calling class
---
.../pump/medtrum/comm/ReadDataPacket.kt | 19 ++++++
.../pump/medtrum/services/BLEComm.kt | 68 +++++++++++--------
.../pump/medtrum/services/MedtrumService.kt | 50 ++++++++++++--
3 files changed, 103 insertions(+), 34 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ReadDataPacket.kt
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ReadDataPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ReadDataPacket.kt
new file mode 100644
index 0000000000..e091cb8f73
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/ReadDataPacket.kt
@@ -0,0 +1,19 @@
+package info.nightscout.pump.medtrum.comm
+
+class ReadDataPacket(data: ByteArray) {
+
+ private var totalData = data.copyOfRange(0, data.size - 1) // Strip crc
+ private var dataSize: Byte = data[0]
+
+ fun addData(newData: ByteArray) {
+ totalData += newData.copyOfRange(4, newData.size - 1) // Strip header and crc
+ }
+
+ fun allDataReceived(): Boolean {
+ return (totalData.size >= dataSize)
+ }
+
+ fun getData(): ByteArray {
+ return totalData
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 316466dbce..dbff1ccc9e 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -32,9 +32,9 @@ import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
-import info.nightscout.pump.medtrum.encryption.Crypt
import info.nightscout.pump.medtrum.comm.WriteCommandPackets
import info.nightscout.pump.medtrum.comm.ManufacturerData
+import info.nightscout.pump.medtrum.comm.ReadDataPacket
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.events.EventPumpStatusChanged
@@ -48,6 +48,14 @@ import java.util.Arrays
import javax.inject.Inject
import javax.inject.Singleton
+interface BLECommCallback {
+
+ open fun onBLEConnected() {}
+ open fun onNotification(notification: ByteArray) {}
+ open fun onIndication(indication: ByteArray) {}
+ open fun onSendMessageError(reason: String)
+}
+
@Singleton
class BLEComm @Inject internal constructor(
private val injector: HasAndroidInjector,
@@ -74,23 +82,28 @@ class BLEComm @Inject internal constructor(
private const val NEEDS_ENABLE = 0x30
private const val MANUFACTURER_ID = 18305
- private const val COMMAND_AUTH_REQ: Byte = 5
}
private val handler =
Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val mBluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
private var mBluetoothGatt: BluetoothGatt? = null
- private val mCrypt = Crypt()
var isConnected = false
var isConnecting = false
private var uartWrite: BluetoothGattCharacteristic? = null
private var uartRead: BluetoothGattCharacteristic? = null
- private var mDeviceSN: Long = 0
-
+ // Read and write buffers
private var mWritePackets = WriteCommandPackets()
+ private var mReadPacket: ReadDataPacket? = null
+
+ private var mDeviceSN: Long = 0
+ private var mCallback: BLECommCallback? = null
+
+ fun setCallback(callback: BLECommCallback?) {
+ this.mCallback = callback
+ }
/** Connect flow: 1. Start scanning for our device (SN entered in settings) */
@SuppressLint("MissingPermission")
@@ -225,14 +238,26 @@ class BLEComm @Inject internal constructor(
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged")
- // TODO: Make split between Notif and Indication
- // Notif contains pump status and alarms
- readDataParsing(characteristic.value)
+
+ val value = characteristic.getValue()
+ if (characteristic.getUuid() == UUID.fromString(READ_UUID)) {
+ mCallback?.onNotification(value)
+ } else if (characteristic.getUuid() == UUID.fromString(WRITE_UUID)) {
+ if (mReadPacket == null) {
+ mReadPacket = ReadDataPacket(value)
+ } else {
+ mReadPacket?.addData(value)
+ }
+ if (mReadPacket?.allDataReceived() == true) {
+ mReadPacket = null
+ mReadPacket?.getData()?.let { mCallback?.onIndication(it) }
+ }
+ }
}
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite status = " + status)
-
+
if (status == BluetoothGatt.GATT_SUCCESS) {
// Check if we need to finish our command!
synchronized(mWritePackets) {
@@ -242,7 +267,7 @@ class BLEComm @Inject internal constructor(
}
}
} else {
- // TODO: What to do here?
+ mCallback?.onSendMessageError("onCharacteristicWrite failure")
}
}
@@ -303,7 +328,10 @@ class BLEComm @Inject internal constructor(
}
if (notificationEnabled) {
aapsLogger.debug(LTag.PUMPBTCOMM, "Notifications enabled!")
- authorize()
+ /** Connect flow: 6. Connected */
+ mCallback?.onBLEConnected()
+ isConnected = true
+ isConnecting = false
}
}
}
@@ -351,23 +379,6 @@ class BLEComm @Inject internal constructor(
}
}
- private fun readDataParsing(receivedData: ByteArray) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< readDataParsing " + Arrays.toString(receivedData))
- // TODO Implement
- // TODO place this at the correct place
- /** Connect flow: 6. Authorized */
- isConnected = true
- isConnecting = false
- }
-
- private fun authorize() {
- aapsLogger.debug(LTag.PUMPBTCOMM, "Start auth!")
- val role = 2 // Fixed to 2 for pump
- val key = mCrypt.keyGen(mDeviceSN)
- val commandData = byteArrayOf(COMMAND_AUTH_REQ) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4)
- sendMessage(commandData)
- }
-
fun sendMessage(message: ByteArray) {
aapsLogger.debug(LTag.PUMPBTCOMM, "sendMessage message = " + Arrays.toString(message))
if (!mWritePackets.allPacketsConsumed()) {
@@ -381,6 +392,7 @@ class BLEComm @Inject internal constructor(
writeCharacteristic(uartWriteBTGattChar, value)
} else {
aapsLogger.error(LTag.PUMPBTCOMM, "sendMessage error in writePacket!")
+ mCallback?.onSendMessageError("error in writePacket!")
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index d4b8e2b674..2b6120d52e 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -23,6 +23,8 @@ import info.nightscout.interfaces.queue.Command
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.medtrum.MedtrumPlugin
+import info.nightscout.pump.medtrum.encryption.Crypt
+import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit
@@ -40,12 +42,13 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
+import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.min
-class MedtrumService : DaggerService() {
+class MedtrumService : DaggerService(), BLECommCallback {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@@ -65,11 +68,19 @@ class MedtrumService : DaggerService() {
@Inject lateinit var pumpSync: PumpSync
@Inject lateinit var dateUtil: DateUtil
+ companion object {
+ private const val COMMAND_AUTH_REQ: Byte = 5
+ }
+
private val disposable = CompositeDisposable()
private val mBinder: IBinder = LocalBinder()
+ private val mCrypt = Crypt()
+
+ private var mDeviceSN: Long = 0
override fun onCreate() {
super.onCreate()
+ bleComm.setCallback(this)
disposable += rxBus
.toObservable(EventAppExit::class.java)
.observeOn(aapsSchedulers.io)
@@ -89,22 +100,20 @@ class MedtrumService : DaggerService() {
fun connect(from: String, deviceSN: Long): Boolean {
// TODO Check we might want to replace this with start scan?
+ mDeviceSN = deviceSN
return bleComm.connect(from, deviceSN)
}
fun stopConnecting() {
+ // TODO proper way for this might need send commands etc
bleComm.stopConnecting()
}
fun disconnect(from: String) {
+ // TODO proper way for this might need send commands etc
bleComm.disconnect(from)
}
- fun sendMessage(message: ByteArray) { // TODO Check what we use here?
- // TODO
- bleComm.sendMessage(message)
- }
-
fun readPumpStatus() {
// TODO
}
@@ -179,6 +188,35 @@ class MedtrumService : DaggerService() {
return false
}
+ private fun authorize() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Start auth!")
+ val role = 2 // Fixed to 2 for pump
+ val key = mCrypt.keyGen(mDeviceSN)
+ val commandData = byteArrayOf(COMMAND_AUTH_REQ) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4)
+ bleComm.sendMessage(commandData)
+ }
+
+ /** BLECommCallbacks */
+ override fun onBLEConnected() {
+ // TODO Replace by FSM Entry?
+ authorize()
+ }
+
+ override fun onNotification(notification: ByteArray) {
+ aapsLogger.debug(LTag.PUMPCOMM, "<<<<< onNotification" + notification.contentToString())
+ // TODO
+ }
+
+ override fun onIndication(indication: ByteArray) {
+ aapsLogger.debug(LTag.PUMPCOMM, "<<<<< onIndication" + indication.contentToString())
+ // TODO
+ }
+
+ override fun onSendMessageError(reason: String) {
+ aapsLogger.debug(LTag.PUMPCOMM, "<<<<< error during send message " + reason)
+ // TODO
+ }
+
/** Service stuff */
inner class LocalBinder : Binder() {
val serviceInstance: MedtrumService
From 27159d6e47e8b7f969ead3ab7e5eac094c82e5fa Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Fri, 24 Feb 2023 20:01:07 +0100
Subject: [PATCH 007/116] Review comments
---
.../androidaps/activities/MyPreferenceFragment.kt | 4 ++--
.../pump/medtrum/services/MedtrumService.kt | 12 ------------
2 files changed, 2 insertions(+), 14 deletions(-)
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
index fc568738ea..7467304b22 100644
--- a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
@@ -123,7 +123,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
@Inject lateinit var wearPlugin: WearPlugin
@Inject lateinit var maintenancePlugin: MaintenancePlugin
@Inject lateinit var eopatchPumpPlugin: EopatchPumpPlugin
- @Inject lateinit var MedtrumPlugin: MedtrumPlugin
+ @Inject lateinit var medtrumPlugin: MedtrumPlugin
@Inject lateinit var passwordCheck: PasswordCheck
@Inject lateinit var nsSettingStatus: NSSettingsStatus
@@ -214,7 +214,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(diaconnG8Plugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(eopatchPumpPlugin, rootKey, config.PUMPDRIVERS)
- addPreferencesFromResourceIfEnabled(MedtrumPlugin, rootKey, config.PUMPDRIVERS)
+ addPreferencesFromResourceIfEnabled(medtrumPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 2b6120d52e..a48ec614d0 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -170,18 +170,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
return false
}
- fun extendedBolus(insulin: Double, durationInHalfHours: Int): Boolean {
- if (!isConnected) return false
- // TODO
- return false
- }
-
- fun extendedBolusStop(): Boolean {
- if (!isConnected) return false
- // TODO
- return false
- }
-
fun updateBasalsInPump(profile: Profile): Boolean {
if (!isConnected) return false
// TODO
From 485826682ef66f701f3996c7e74ef6be197e18ad Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 26 Feb 2023 19:41:41 +0100
Subject: [PATCH 008/116] Implemented state to initialize pump connection
---
.../pump/medtrum/comm/WriteCommand.kt | 61 ++++
.../pump/medtrum/services/BLEComm.kt | 13 +-
.../pump/medtrum/services/MedtrumService.kt | 264 +++++++++++++++---
.../pump/medtrum/util/MedtrumTimeUtil.kt | 20 ++
4 files changed, 307 insertions(+), 51 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommand.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommand.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommand.kt
new file mode 100644
index 0000000000..ceb8902040
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommand.kt
@@ -0,0 +1,61 @@
+package info.nightscout.pump.medtrum.comm
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.encryption.Crypt
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import info.nightscout.shared.utils.DateUtil
+import javax.inject.Inject
+import javax.inject.Singleton
+
+// TODO object would be better? Or split this class up in an entirely different way
+@Singleton
+class WriteCommand @Inject internal constructor(
+ private val dateUtil: DateUtil
+) {
+
+ val COMMAND_SYNCHRONIZE: Byte = 3
+ val COMMAND_SUBSCRIBE: Byte = 4
+ val COMMAND_AUTH_REQ: Byte = 5
+ val COMMAND_GET_DEVICE_TYPE: Byte = 6
+ val COMMAND_SET_TIME: Byte = 10
+ val COMMAND_GET_TIME: Byte = 11
+ val COMMAND_SET_TIME_ZONE: Byte = 12
+
+ private val mCrypt = Crypt()
+ private val timeUtil = MedtrumTimeUtil()
+
+ fun authorize(deviceSerial: Long): ByteArray {
+ val role = 2 // Fixed to 2 for pump
+ val key = mCrypt.keyGen(deviceSerial)
+ return byteArrayOf(COMMAND_AUTH_REQ) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4)
+ }
+
+ fun getDeviceType(): ByteArray {
+ return byteArrayOf(COMMAND_GET_DEVICE_TYPE)
+ }
+
+ fun getTime(): ByteArray {
+ return byteArrayOf(COMMAND_GET_TIME)
+ }
+
+ fun setTime(): ByteArray {
+ val time = timeUtil.getCurrentTimePumpSeconds()
+ return byteArrayOf(COMMAND_SET_TIME) + 2.toByte() + time.toByteArray(4)
+ }
+
+ fun setTimeZone(): ByteArray {
+ val time = timeUtil.getCurrentTimePumpSeconds()
+ var offsetMins = dateUtil.getTimeZoneOffsetMinutes(dateUtil.now())
+ if (offsetMins < 0) offsetMins += 65536
+ return byteArrayOf(COMMAND_SET_TIME_ZONE) + offsetMins.toByteArray(2) + time.toByteArray(4)
+ }
+
+ fun synchronize(): ByteArray {
+ return byteArrayOf(COMMAND_SYNCHRONIZE)
+ }
+
+ fun subscribe(): ByteArray {
+ return byteArrayOf(COMMAND_SUBSCRIBE) + 4095.toByteArray(2)
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index dbff1ccc9e..b6ad902279 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -49,11 +49,10 @@ import javax.inject.Inject
import javax.inject.Singleton
interface BLECommCallback {
-
- open fun onBLEConnected() {}
- open fun onNotification(notification: ByteArray) {}
- open fun onIndication(indication: ByteArray) {}
- open fun onSendMessageError(reason: String)
+ fun onBLEConnected()
+ fun onNotification(notification: ByteArray)
+ fun onIndication(indication: ByteArray)
+ fun onSendMessageError(reason: String)
}
@Singleton
@@ -237,7 +236,7 @@ class BLEComm @Inject internal constructor(
}
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
- aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged")
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged data: " + characteristic.value + "UUID: " + characteristic.getUuid().toString())
val value = characteristic.getValue()
if (characteristic.getUuid() == UUID.fromString(READ_UUID)) {
@@ -249,8 +248,8 @@ class BLEComm @Inject internal constructor(
mReadPacket?.addData(value)
}
if (mReadPacket?.allDataReceived() == true) {
- mReadPacket = null
mReadPacket?.getData()?.let { mCallback?.onIndication(it) }
+ mReadPacket = null
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index a48ec614d0..aa9fd7e552 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -23,8 +23,10 @@ import info.nightscout.interfaces.queue.Command
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.medtrum.MedtrumPlugin
-import info.nightscout.pump.medtrum.encryption.Crypt
-import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.comm.WriteCommand
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.extension.toLong
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit
@@ -38,6 +40,7 @@ import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
+import io.reactivex.rxjava3.core.ObservableEmitter
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import org.joda.time.DateTime
@@ -67,16 +70,18 @@ class MedtrumService : DaggerService(), BLECommCallback {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var pumpSync: PumpSync
@Inject lateinit var dateUtil: DateUtil
+ @Inject lateinit var writeCommand: WriteCommand
- companion object {
- private const val COMMAND_AUTH_REQ: Byte = 5
- }
+ val timeUtil = MedtrumTimeUtil()
private val disposable = CompositeDisposable()
private val mBinder: IBinder = LocalBinder()
- private val mCrypt = Crypt()
private var mDeviceSN: Long = 0
+ private var currentState: State = IdleState()
+
+ // TODO: Stuff like this in a settings class?
+ private var mLastDeviceTime: Long = 0
override fun onCreate() {
super.onCreate()
@@ -106,12 +111,12 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun stopConnecting() {
// TODO proper way for this might need send commands etc
- bleComm.stopConnecting()
+ // bleComm.stopConnecting()
}
fun disconnect(from: String) {
// TODO proper way for this might need send commands etc
- bleComm.disconnect(from)
+ // bleComm.disconnect(from)
}
fun readPumpStatus() {
@@ -145,49 +150,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
// TODO
}
- fun tempBasal(percent: Int, durationInHours: Int): Boolean {
- // TODO
- return false
- }
-
- fun highTempBasal(percent: Int): Boolean {
- // TODO
- return false
- }
-
- fun tempBasalShortDuration(percent: Int, durationInMinutes: Int): Boolean {
- if (durationInMinutes != 15 && durationInMinutes != 30) {
- aapsLogger.error(LTag.PUMPCOMM, "Wrong duration param")
- return false
- }
- // TODO
- return false
- }
-
- fun tempBasalStop(): Boolean {
- if (!isConnected) return false
- // TODO
- return false
- }
-
fun updateBasalsInPump(profile: Profile): Boolean {
if (!isConnected) return false
// TODO
return false
}
- private fun authorize() {
- aapsLogger.debug(LTag.PUMPCOMM, "Start auth!")
- val role = 2 // Fixed to 2 for pump
- val key = mCrypt.keyGen(mDeviceSN)
- val commandData = byteArrayOf(COMMAND_AUTH_REQ) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4)
- bleComm.sendMessage(commandData)
- }
-
/** BLECommCallbacks */
override fun onBLEConnected() {
- // TODO Replace by FSM Entry?
- authorize()
+ currentState.onConnected()
}
override fun onNotification(notification: ByteArray) {
@@ -197,7 +168,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onIndication(indication: ByteArray) {
aapsLogger.debug(LTag.PUMPCOMM, "<<<<< onIndication" + indication.contentToString())
- // TODO
+ currentState.onIndication(indication)
}
override fun onSendMessageError(reason: String) {
@@ -207,6 +178,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
/** Service stuff */
inner class LocalBinder : Binder() {
+
val serviceInstance: MedtrumService
get() = this@MedtrumService
}
@@ -218,4 +190,208 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
return Service.START_STICKY
}
+
+ /**
+ * States are used to keep track of the communication and to guide the flow
+ */
+ private fun toState(nextState: State) {
+ currentState = nextState
+ currentState.onEnter()
+ }
+
+ // State class, Can we move this to different file?
+ private abstract inner class State {
+
+ open fun onEnter() {}
+ open fun onIndication(data: ByteArray) {
+ aapsLogger.debug(LTag.PUMPCOMM, "onIndicationr: " + this.toString() + "Should not be called here!")
+ }
+
+ open fun onConnected() {}
+ }
+
+ private inner class IdleState : State() {
+
+ override fun onConnected() {
+ toState(AuthState())
+ }
+ }
+
+ private inner class AuthState : State() {
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached AuthState")
+ bleComm.sendMessage(writeCommand.authorize(mDeviceSN))
+ }
+
+ override fun onIndication(data: ByteArray) {
+ // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
+ val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
+ val responseCode = data.copyOfRange(4, 6).toInt()
+ // TODO Get pump version info (do we care?)
+ if (responseCode == 0 && commandCode == writeCommand.COMMAND_AUTH_REQ) {
+ // Succes!
+ toState(GetDeviceTypeState())
+ } else {
+ // Failure
+ bleComm.disconnect("Failure")
+ toState(IdleState())
+ }
+ }
+ }
+
+ private inner class GetDeviceTypeState : State() {
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached GetDeviceTypeState")
+ bleComm.sendMessage(writeCommand.getDeviceType())
+ }
+
+ override fun onIndication(data: ByteArray) {
+ // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
+ val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
+ val responseCode = data.copyOfRange(4, 6).toInt()
+ // TODO Get device type (do we care?)
+ if (responseCode == 0 && commandCode == writeCommand.COMMAND_GET_DEVICE_TYPE) {
+ // Succes!
+ toState(GetTimeState())
+ } else {
+ // Failure
+ bleComm.disconnect("Failure")
+ toState(IdleState())
+ }
+ }
+ }
+
+ private inner class GetTimeState : State() {
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached GetTimeState")
+ bleComm.sendMessage(writeCommand.getTime())
+ }
+
+ override fun onIndication(data: ByteArray) {
+ // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
+ val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
+ val responseCode = data.copyOfRange(4, 6).toInt()
+ val time = data.copyOfRange(6, 10).toLong()
+ if (responseCode == 0 && commandCode == writeCommand.COMMAND_GET_TIME) {
+ // Succes!
+ mLastDeviceTime = time
+ val currTimeSec = dateUtil.nowWithoutMilliseconds() / 1000
+ if (abs(timeUtil.convertPumpTimeToSystemTimeSeconds(time) - currTimeSec) <= 5) { // Allow 5 sec deviation
+ toState(SynchronizeState())
+ } else {
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "GetTimeState.onIndication need to set time. systemTime: " + currTimeSec + " PumpTime: " + time + " Pump Time to system time: " + timeUtil.convertPumpTimeToSystemTimeSeconds(
+ time
+ )
+ )
+ toState(SetTimeState())
+ }
+ } else {
+ // Failure
+ bleComm.disconnect("Failure")
+ toState(IdleState())
+ }
+ }
+ }
+
+ private inner class SetTimeState : State() {
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SetTimeState")
+ bleComm.sendMessage(writeCommand.setTime())
+ }
+
+ override fun onIndication(data: ByteArray) {
+ // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
+ val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
+ val responseCode = data.copyOfRange(4, 6).toInt()
+ if (responseCode == 0 && commandCode == writeCommand.COMMAND_SET_TIME) {
+ // Succes!
+ toState(SetTimeZoneState())
+ } else {
+ // Failure
+ bleComm.disconnect("Failure")
+ toState(IdleState())
+ }
+ }
+ }
+
+ private inner class SetTimeZoneState : State() {
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SetTimeZoneState")
+ bleComm.sendMessage(writeCommand.setTimeZone())
+ }
+
+ override fun onIndication(data: ByteArray) {
+ // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
+ val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
+ val responseCode = data.copyOfRange(4, 6).toInt()
+ if (responseCode == 0 && commandCode == writeCommand.COMMAND_SET_TIME_ZONE) {
+ // Succes!
+ toState(SynchronizeState())
+ } else {
+ // Failure
+ bleComm.disconnect("Failure")
+ toState(IdleState())
+ }
+ }
+ }
+
+ private inner class SynchronizeState : State() {
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SynchronizeState")
+ bleComm.sendMessage(writeCommand.synchronize())
+ }
+
+ override fun onIndication(data: ByteArray) {
+ // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
+ val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
+ val responseCode = data.copyOfRange(4, 6).toInt()
+ if (responseCode == 0 && commandCode == writeCommand.COMMAND_SYNCHRONIZE) {
+ // Succes!
+ // TODO: Handle pump state parameters
+ toState(SubscribeState())
+ } else {
+ // Failure
+ bleComm.disconnect("Failure")
+ toState(IdleState())
+ }
+ }
+ }
+
+ private inner class SubscribeState : State() {
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SubscribeState")
+ bleComm.sendMessage(writeCommand.subscribe())
+ }
+
+ override fun onIndication(data: ByteArray) {
+ // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
+ val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
+ val responseCode = data.copyOfRange(4, 6).toInt()
+ if (responseCode == 0 && commandCode == writeCommand.COMMAND_SUBSCRIBE) {
+ // Succes!
+ toState(ReadyState())
+ } else {
+ // Failure
+ bleComm.disconnect("Failure")
+ toState(IdleState())
+ }
+ }
+ }
+
+ private inner class ReadyState : State() {
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!")
+ }
+ // Just a placeholder, this state is reached when the patch is ready to receive commands (Bolus, temp basal and whatever)
+ }
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
new file mode 100644
index 0000000000..256bb850a0
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
@@ -0,0 +1,20 @@
+package info.nightscout.pump.medtrum.util
+
+import java.time.Duration
+import java.time.Instant
+
+class MedtrumTimeUtil {
+
+ fun getCurrentTimePumpSeconds() : Long {
+ val startInstant = Instant.parse("2020-01-01T00:00:00Z")
+ val currentInstant = Instant.now()
+ return Duration.between(startInstant, currentInstant).seconds
+ }
+
+ fun convertPumpTimeToSystemTimeSeconds(pumpTime: Long) : Long {
+ val startInstant = Instant.parse("2020-01-01T00:00:00Z")
+ val pumpInstant = startInstant.plusSeconds(pumpTime)
+ val epochInstant = Instant.EPOCH
+ return Duration.between(epochInstant, pumpInstant).seconds
+ }
+}
\ No newline at end of file
From 43515f7b17e7b3b45e7b5a14e0ec53aef4fb06db Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 28 Feb 2023 08:29:45 +0100
Subject: [PATCH 009/116] Buttons in overview
---
pump/medtrum/build.gradle | 5 +-
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 4 +-
.../medtrum/di/MedtrumActivitiesModule.kt | 13 -
.../pump/medtrum/di/MedtrumInjectHelpers.kt | 12 +
.../pump/medtrum/di/MedtrumModule.kt | 47 ++-
.../pump/medtrum/di/MedtrumServicesModule.kt | 11 -
.../pump/medtrum/ui/BaseNavigator.kt | 7 +
...Fragment.kt => MedtrumOverviewFragment.kt} | 10 +-
.../medtrum/ui/viewmodel/BaseViewModel.kt | 31 ++
.../medtrum/ui/viewmodel/OverviewViewModel.kt | 31 ++
.../medtrum/ui/viewmodel/ViewModelFactory.kt | 40 +++
.../res/layout/medtrum_overview_fragment.xml | 304 +++++++++++++++++
.../main/res/layout/medtrum_pump_fragment.xml | 306 ------------------
pump/medtrum/src/main/res/values/strings.xml | 2 +
14 files changed, 479 insertions(+), 344 deletions(-)
delete mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumActivitiesModule.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumInjectHelpers.kt
delete mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumServicesModule.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/BaseNavigator.kt
rename pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/{MedtrumPumpFragment.kt => MedtrumOverviewFragment.kt} (90%)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/OverviewViewModel.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/ViewModelFactory.kt
create mode 100644 pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml
delete mode 100644 pump/medtrum/src/main/res/layout/medtrum_pump_fragment.xml
diff --git a/pump/medtrum/build.gradle b/pump/medtrum/build.gradle
index 9163baf95a..c24e386377 100644
--- a/pump/medtrum/build.gradle
+++ b/pump/medtrum/build.gradle
@@ -13,13 +13,16 @@ apply from: "${project.rootDir}/core/main/test_dependencies.gradle"
apply from: "${project.rootDir}/core/main/jacoco_global.gradle"
android {
-
namespace 'info.nightscout.pump.medtrum'
+ dataBinding {
+ enabled = true
+ }
}
dependencies {
implementation project(':app-wear-shared:shared')
implementation project(':database:entities')
+ implementation project(':core:libraries')
implementation project(':core:interfaces')
implementation project(':core:main')
implementation project(':core:ui')
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index f799d15e51..959fac5b59 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -26,7 +26,7 @@ import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.queue.CustomCommand
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.TimeChangeType
-import info.nightscout.pump.medtrum.ui.MedtrumPumpFragment
+import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
import info.nightscout.pump.medtrum.services.MedtrumService
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
@@ -67,7 +67,7 @@ class MedtrumPlugin @Inject constructor(
) : PumpPluginBase(
PluginDescription()
.mainType(PluginType.PUMP)
- .fragmentClass(MedtrumPumpFragment::class.java.name)
+ .fragmentClass(MedtrumOverviewFragment::class.java.name)
.pluginIcon(info.nightscout.core.ui.R.drawable.ic_eopatch2_128) // TODO
.pluginName(R.string.medtrum)
.shortName(R.string.medtrum_pump_shortname)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumActivitiesModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumActivitiesModule.kt
deleted file mode 100644
index 8bac156f22..0000000000
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumActivitiesModule.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package info.nightscout.pump.medtrum.di
-
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-import info.nightscout.pump.medtrum.ui.MedtrumPumpFragment
-
-@Module
-@Suppress("unused")
-abstract class MedtrumActivitiesModule {
-
- @ContributesAndroidInjector abstract fun contributesMedtrumPumpFragment(): MedtrumPumpFragment
-
-}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumInjectHelpers.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumInjectHelpers.kt
new file mode 100644
index 0000000000..96118f4670
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumInjectHelpers.kt
@@ -0,0 +1,12 @@
+package info.nightscout.pump.medtrum.di
+
+import javax.inject.Qualifier
+import javax.inject.Scope
+
+@Qualifier
+annotation class MedtrumPluginQualifier
+
+@MustBeDocumented
+@Scope
+@Retention(AnnotationRetention.RUNTIME)
+annotation class FragmentScope
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
index 612053b6ec..9fcaf5d9d8 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
@@ -1,9 +1,46 @@
package info.nightscout.pump.medtrum.di
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import dagger.Binds
import dagger.Module
+import dagger.Provides
+import dagger.android.ContributesAndroidInjector
+import dagger.multibindings.IntoMap
+// import info.nightscout.androidaps.plugins.pump.eopatch.ui.viewmodel.OverviewViewModel
+import info.nightscout.pump.medtrum.services.MedtrumService
+import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.OverviewViewModel
+// import info.nightscout.pump.medtrum.ui.viewmodel.ViewModel
+import info.nightscout.pump.medtrum.ui.viewmodel.ViewModelFactory
+import info.nightscout.pump.medtrum.ui.viewmodel.ViewModelKey
+import javax.inject.Provider
-@Module(includes = [
- MedtrumActivitiesModule::class,
- MedtrumServicesModule::class
-])
-open class MedtrumModule
\ No newline at end of file
+
+@Module
+@Suppress("unused")
+abstract class MedtrumModule {
+ companion object {
+
+ @Provides
+ @MedtrumPluginQualifier
+ fun providesViewModelFactory(@MedtrumPluginQualifier viewModels: MutableMap, @JvmSuppressWildcards Provider>): ViewModelProvider.Factory {
+ return ViewModelFactory(viewModels)
+ }
+ }
+
+ // VIEW MODELS
+ @Binds
+ @IntoMap
+ @MedtrumPluginQualifier
+ @ViewModelKey(OverviewViewModel::class)
+ internal abstract fun bindsOverviewViewmodel(viewModel: OverviewViewModel): ViewModel
+
+ // FRAGMENTS
+ @ContributesAndroidInjector
+ abstract fun contributesMedtrumOverviewFragment(): MedtrumOverviewFragment
+
+ // SERVICE
+ @ContributesAndroidInjector
+ abstract fun contributesDanaRSService(): MedtrumService
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumServicesModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumServicesModule.kt
deleted file mode 100644
index 0c587bacc2..0000000000
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumServicesModule.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package info.nightscout.pump.medtrum.di
-
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-import info.nightscout.pump.medtrum.services.MedtrumService
-
-@Module
-@Suppress("unused")
-abstract class MedtrumServicesModule {
- @ContributesAndroidInjector abstract fun contributesDanaRSService(): MedtrumService
-}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/BaseNavigator.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/BaseNavigator.kt
new file mode 100644
index 0000000000..c1bebb0a93
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/BaseNavigator.kt
@@ -0,0 +1,7 @@
+package info.nightscout.pump.medtrum.ui
+
+interface BaseNavigator {
+ fun back()
+
+ fun finish(finishAffinity: Boolean = false)
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
similarity index 90%
rename from pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt
rename to pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index ac94004d8b..76f36dded1 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPumpFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -11,7 +11,7 @@ import info.nightscout.core.extensions.toStringFull
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.profile.ProfileFunction
-import info.nightscout.pump.medtrum.databinding.MedtrumPumpFragmentBinding
+import info.nightscout.pump.medtrum.databinding.MedtrumOverviewFragmentBinding
import info.nightscout.pump.medtrum.events.EventMedtrumPumpUpdateGui
import info.nightscout.pump.medtrum.MedtrumPlugin
import info.nightscout.rx.AapsSchedulers
@@ -25,7 +25,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject
-class MedtrumPumpFragment : DaggerFragment() {
+class MedtrumOverviewFragment : DaggerFragment() {
@Inject lateinit var rxBus: RxBus
@Inject lateinit var rh: ResourceHelper
@@ -41,14 +41,14 @@ class MedtrumPumpFragment : DaggerFragment() {
private lateinit var refreshLoop: Runnable
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
- private var _binding: MedtrumPumpFragmentBinding? = null
+ private var _binding: MedtrumOverviewFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
- MedtrumPumpFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
+ MedtrumOverviewFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
@Synchronized
override fun onResume() {
@@ -93,8 +93,6 @@ class MedtrumPumpFragment : DaggerFragment() {
binding.baseBasalRate.text = rh.gs(info.nightscout.core.ui.R.string.pump_base_basal_rate, MedtrumPlugin.baseBasalRate)
binding.tempbasal.text = iobCobCalculator.getTempBasal(dateUtil.now())?.toStringFull(profile, dateUtil)
?: ""
- binding.extendedbolus.text = iobCobCalculator.getExtendedBolus(dateUtil.now())?.toStringFull(dateUtil)
- ?: ""
binding.battery.text = rh.gs(info.nightscout.core.ui.R.string.format_percent, 0) // TODO
binding.reservoir.text = rh.gs(info.nightscout.interfaces.R.string.format_insulin_units, 0.0) // TODO
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
new file mode 100644
index 0000000000..2ff064649f
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
@@ -0,0 +1,31 @@
+package info.nightscout.pump.medtrum.ui.viewmodel
+
+import androidx.lifecycle.ViewModel
+import info.nightscout.pump.medtrum.ui.BaseNavigator
+import io.reactivex.rxjava3.disposables.CompositeDisposable
+import io.reactivex.rxjava3.disposables.Disposable
+import java.lang.ref.WeakReference
+
+abstract class BaseViewModel : ViewModel() {
+
+ private var _navigator: WeakReference? = null
+ var navigator: N?
+ set(value) {
+ _navigator = WeakReference(value)
+ }
+ get() = _navigator?.get()
+
+ private val compositeDisposable = CompositeDisposable()
+
+ override fun onCleared() {
+ compositeDisposable.clear()
+ super.onCleared()
+ }
+
+ fun back() = navigator?.back()
+
+ fun finish() = navigator?.finish()
+
+ fun Disposable.addTo() = apply { compositeDisposable.add(this) }
+
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/OverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/OverviewViewModel.kt
new file mode 100644
index 0000000000..c2288e5e23
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/OverviewViewModel.kt
@@ -0,0 +1,31 @@
+package info.nightscout.pump.medtrum.ui.viewmodel
+
+import info.nightscout.pump.medtrum.ui.BaseNavigator
+import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class OverviewViewModel @Inject constructor(
+ private val aapsLogger: AAPSLogger
+) : BaseViewModel() {
+
+ val isPatchActivated : Boolean
+ get() = false // TODO
+ val isPatchConnected: Boolean
+ get() = false // TODO
+
+ init {
+ // TODO
+ }
+
+ fun onClickActivation(){
+ aapsLogger.debug(LTag.PUMP, "Start Patch clicked!")
+ // TODO
+ }
+
+ fun onClickDeactivation(){
+ aapsLogger.debug(LTag.PUMP, "Stop Patch clicked!")
+ // TODO
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/ViewModelFactory.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/ViewModelFactory.kt
new file mode 100644
index 0000000000..6acf7d4404
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/ViewModelFactory.kt
@@ -0,0 +1,40 @@
+package info.nightscout.pump.medtrum.ui.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import dagger.MapKey
+import javax.inject.Inject
+import javax.inject.Provider
+import javax.inject.Singleton
+import kotlin.reflect.KClass
+
+@MustBeDocumented
+@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
+@Retention(AnnotationRetention.RUNTIME)
+@MapKey
+internal annotation class ViewModelKey(val value: KClass)
+
+@Singleton
+class ViewModelFactory @Inject constructor(private val creators: Map, @JvmSuppressWildcards Provider>) : ViewModelProvider.Factory {
+ override fun create(modelClass: Class): T {
+ var creator: Provider? = creators[modelClass]
+ if (creator == null) {
+ for ((key, value) in creators) {
+ if (modelClass.isAssignableFrom(key)) {
+ creator = value
+ break
+ }
+ }
+ }
+ if (creator == null) {
+ throw IllegalArgumentException("unknown model class $modelClass")
+ }
+ try {
+ @Suppress("UNCHECKED_CAST")
+ return creator.get() as T
+ } catch (e: Exception) {
+ throw IllegalStateException(e)
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml b/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml
new file mode 100644
index 0000000000..f104a351de
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml
@@ -0,0 +1,304 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/medtrum_pump_fragment.xml b/pump/medtrum/src/main/res/layout/medtrum_pump_fragment.xml
deleted file mode 100644
index 222bed82df..0000000000
--- a/pump/medtrum/src/main/res/layout/medtrum_pump_fragment.xml
+++ /dev/null
@@ -1,306 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index b361dec76e..36925f83d3 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -13,5 +13,7 @@
SN
Serial number pump base
+ Start new patch
+ Stop patch
From 8f6dfbdf88fcbaba5e1ee438ca7d1d5b378e703e Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 2 Mar 2023 18:32:30 +0100
Subject: [PATCH 010/116] Overview fragment based on eopatch layout
---
.../bindingadapters/OnSafeClickListener.kt | 26 ++
.../bindingadapters/ViewBindingAdapter.kt | 29 +++
.../pump/medtrum/di/MedtrumModule.kt | 8 +-
.../pump/medtrum/extension/ViewExtension.kt | 34 +++
.../pump/medtrum/ui/MedtrumBaseActivity.kt | 58 +++++
.../pump/medtrum/ui/MedtrumBaseFragment.kt | 66 +++++
...seNavigator.kt => MedtrumBaseNavigator.kt} | 2 +-
.../medtrum/ui/MedtrumOverviewFragment.kt | 122 ++++-----
.../medtrum/ui/viewmodel/BaseViewModel.kt | 4 +-
...ewModel.kt => MedtrumOverviewViewModel.kt} | 8 +-
.../res/layout/medtrum_overview_fragment.xml | 243 +++---------------
pump/medtrum/src/main/res/values/strings.xml | 5 +-
12 files changed, 303 insertions(+), 302 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/bindingadapters/OnSafeClickListener.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/bindingadapters/ViewBindingAdapter.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/ViewExtension.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseActivity.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseFragment.kt
rename pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/{BaseNavigator.kt => MedtrumBaseNavigator.kt} (76%)
rename pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/{OverviewViewModel.kt => MedtrumOverviewViewModel.kt} (75%)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/bindingadapters/OnSafeClickListener.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/bindingadapters/OnSafeClickListener.kt
new file mode 100644
index 0000000000..49648a3d20
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/bindingadapters/OnSafeClickListener.kt
@@ -0,0 +1,26 @@
+package info.nightscout.pump.medtrum.bindingadapters
+
+import android.view.View
+import java.util.concurrent.atomic.AtomicBoolean
+
+class OnSafeClickListener(
+ private val clickListener: View.OnClickListener,
+ private val intervalMs: Long = MIN_CLICK_INTERVAL
+) : View.OnClickListener {
+ private var canClick = AtomicBoolean(true)
+
+ override fun onClick(v: View?) {
+ if (canClick.getAndSet(false)) {
+ v?.run {
+ postDelayed({
+ canClick.set(true)
+ }, intervalMs)
+ clickListener.onClick(v)
+ }
+ }
+ }
+ companion object {
+ // 중복 클릭 방지 시간 설정
+ private const val MIN_CLICK_INTERVAL: Long = 1000
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/bindingadapters/ViewBindingAdapter.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/bindingadapters/ViewBindingAdapter.kt
new file mode 100644
index 0000000000..f4b51efe1a
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/bindingadapters/ViewBindingAdapter.kt
@@ -0,0 +1,29 @@
+package info.nightscout.pump.medtrum.bindingadapters
+
+import android.view.View
+import android.widget.TextView
+import androidx.annotation.ColorRes
+import androidx.databinding.BindingAdapter
+import info.nightscout.pump.medtrum.extension.setVisibleOrGone
+
+@BindingAdapter("android:visibility")
+fun setVisibility(view: View, visible: Boolean) {
+ view.setVisibleOrGone(visible)
+}
+
+@BindingAdapter("visibleOrGone")
+fun setVisibleOrGone(view: View, visibleOrGone: Boolean) {
+ view.setVisibleOrGone(visibleOrGone)
+}
+
+@BindingAdapter("onSafeClick")
+fun View.setOnSafeClickListener(clickListener: View.OnClickListener?) {
+ clickListener?.also {
+ setOnClickListener(OnSafeClickListener(it))
+ } ?: setOnClickListener(null)
+}
+
+@BindingAdapter("textColor")
+fun setTextColor(view: TextView, @ColorRes colorResId: Int) {
+ view.setTextColor(view.context.getColor(colorResId))
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
index 9fcaf5d9d8..71af92437e 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
@@ -7,11 +7,9 @@ import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoMap
-// import info.nightscout.androidaps.plugins.pump.eopatch.ui.viewmodel.OverviewViewModel
import info.nightscout.pump.medtrum.services.MedtrumService
import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
-import info.nightscout.pump.medtrum.ui.viewmodel.OverviewViewModel
-// import info.nightscout.pump.medtrum.ui.viewmodel.ViewModel
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
import info.nightscout.pump.medtrum.ui.viewmodel.ViewModelFactory
import info.nightscout.pump.medtrum.ui.viewmodel.ViewModelKey
import javax.inject.Provider
@@ -33,8 +31,8 @@ abstract class MedtrumModule {
@Binds
@IntoMap
@MedtrumPluginQualifier
- @ViewModelKey(OverviewViewModel::class)
- internal abstract fun bindsOverviewViewmodel(viewModel: OverviewViewModel): ViewModel
+ @ViewModelKey(MedtrumOverviewViewModel::class)
+ internal abstract fun bindsMedtrumOverviewViewmodel(viewModel: MedtrumOverviewViewModel): ViewModel
// FRAGMENTS
@ContributesAndroidInjector
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/ViewExtension.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/ViewExtension.kt
new file mode 100644
index 0000000000..5cf65baeb6
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/ViewExtension.kt
@@ -0,0 +1,34 @@
+package info.nightscout.pump.medtrum.extension
+
+import android.view.View
+
+fun View?.visible() = this?.run { visibility = View.VISIBLE }
+
+fun View?.visible(vararg views: View?) {
+ visible()
+ for (view in views)
+ view.visible()
+}
+
+fun View?.invisible() = this?.run { visibility = View.INVISIBLE }
+
+fun View?.invisible(vararg views: View?) {
+ invisible()
+ for (view in views)
+ view.invisible()
+}
+
+fun View?.gone() = this?.run { visibility = View.GONE }
+
+fun View?.gone(vararg views: View?) {
+ gone()
+ for (view in views)
+ view.gone()
+}
+
+fun View?.setVisibleOrGone(visibleOrGone: Boolean, vararg views: View?) {
+ for (view in views)
+ if (visibleOrGone) view.visible() else view.gone()
+}
+
+fun View?.setVisibleOrGone(visibleOrGone: Boolean) = setVisibleOrGone(visibleOrGone, this)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseActivity.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseActivity.kt
new file mode 100644
index 0000000000..65b570f5c8
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseActivity.kt
@@ -0,0 +1,58 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.activity.result.ActivityResultLauncher
+import androidx.annotation.LayoutRes
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+import androidx.lifecycle.ViewModelProvider
+import dagger.android.support.DaggerAppCompatActivity
+import info.nightscout.core.ui.R
+import info.nightscout.pump.medtrum.di.MedtrumPluginQualifier
+import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
+import info.nightscout.rx.AapsSchedulers
+import io.reactivex.rxjava3.disposables.CompositeDisposable
+import javax.inject.Inject
+
+abstract class MedtrumBaseActivity : DaggerAppCompatActivity(), MedtrumBaseNavigator {
+ @Inject
+ @MedtrumPluginQualifier
+ lateinit var viewModelFactory: ViewModelProvider.Factory
+
+ @Inject lateinit var aapsSchedulers: AapsSchedulers
+
+ protected lateinit var binding: B
+
+ private val compositeDisposable = CompositeDisposable()
+
+ protected lateinit var getResult: ActivityResultLauncher
+
+ @LayoutRes
+ abstract fun getLayoutId(): Int
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setTheme(R.style.AppTheme_NoActionBar)
+
+ binding = DataBindingUtil.setContentView(this, getLayoutId())
+ binding.lifecycleOwner = this
+
+ }
+
+ override fun back() {
+ if(supportFragmentManager.backStackEntryCount == 0) {
+ finish()
+ } else {
+ supportFragmentManager.popBackStack()
+ }
+ }
+
+ override fun finish(finishAffinity: Boolean) {
+ if(finishAffinity) {
+ finishAffinity()
+ } else {
+ finish()
+ }
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseFragment.kt
new file mode 100644
index 0000000000..e09a283c0d
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseFragment.kt
@@ -0,0 +1,66 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.CallSuper
+import androidx.annotation.LayoutRes
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+import androidx.lifecycle.ViewModelProvider
+import dagger.android.support.DaggerFragment
+import info.nightscout.pump.medtrum.di.MedtrumPluginQualifier
+import io.reactivex.rxjava3.disposables.CompositeDisposable
+import javax.inject.Inject
+
+abstract class MedtrumBaseFragment : DaggerFragment(), MedtrumBaseNavigator {
+ @Inject
+ @MedtrumPluginQualifier
+ lateinit var viewModelFactory: ViewModelProvider.Factory
+
+ protected var baseActivity: MedtrumBaseActivity<*>? = null
+
+ protected lateinit var binding: B
+
+ private val compositeDisposable = CompositeDisposable()
+
+ @LayoutRes
+ abstract fun getLayoutId(): Int
+
+ @CallSuper
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+ if (context is MedtrumBaseActivity<*>) {
+ baseActivity = context
+ }
+ }
+
+ @CallSuper
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ binding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false)
+ binding.lifecycleOwner = viewLifecycleOwner
+ return binding.root
+ }
+
+ @CallSuper
+ override fun onDestroy() {
+ super.onDestroy()
+ compositeDisposable.dispose()
+ }
+
+ @CallSuper
+ override fun onDetach() {
+ super.onDetach()
+ baseActivity = null
+ }
+
+ override fun back() {
+ baseActivity?.back()
+ }
+
+ override fun finish(finishAffinity: Boolean) {
+ baseActivity?.finish(finishAffinity)
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/BaseNavigator.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseNavigator.kt
similarity index 76%
rename from pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/BaseNavigator.kt
rename to pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseNavigator.kt
index c1bebb0a93..ebd597a673 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/BaseNavigator.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumBaseNavigator.kt
@@ -1,6 +1,6 @@
package info.nightscout.pump.medtrum.ui
-interface BaseNavigator {
+interface MedtrumBaseNavigator {
fun back()
fun finish(finishAffinity: Boolean = false)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index 76f36dded1..a29b8c60ad 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -1,101 +1,67 @@
package info.nightscout.pump.medtrum.ui
+import android.content.Intent
import android.os.Bundle
-import android.os.Handler
-import android.os.HandlerThread
-import android.view.LayoutInflater
import android.view.View
-import android.view.ViewGroup
-import dagger.android.support.DaggerFragment
-import info.nightscout.core.extensions.toStringFull
-import info.nightscout.core.utils.fabric.FabricPrivacy
-import info.nightscout.interfaces.iob.IobCobCalculator
-import info.nightscout.interfaces.profile.ProfileFunction
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.lifecycle.ViewModelProvider
import info.nightscout.pump.medtrum.databinding.MedtrumOverviewFragmentBinding
-import info.nightscout.pump.medtrum.events.EventMedtrumPumpUpdateGui
-import info.nightscout.pump.medtrum.MedtrumPlugin
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
+import info.nightscout.pump.medtrum.R
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
-import info.nightscout.rx.events.EventExtendedBolusChange
-import info.nightscout.rx.events.EventTempBasalChange
-import info.nightscout.shared.interfaces.ResourceHelper
-import info.nightscout.shared.utils.DateUtil
-import info.nightscout.shared.utils.T
+import info.nightscout.rx.logging.AAPSLogger
import io.reactivex.rxjava3.disposables.CompositeDisposable
-import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject
-class MedtrumOverviewFragment : DaggerFragment() {
+class MedtrumOverviewFragment : MedtrumBaseFragment() {
@Inject lateinit var rxBus: RxBus
- @Inject lateinit var rh: ResourceHelper
- @Inject lateinit var dateUtil: DateUtil
- @Inject lateinit var fabricPrivacy: FabricPrivacy
- @Inject lateinit var MedtrumPlugin: MedtrumPlugin
- @Inject lateinit var profileFunction: ProfileFunction
- @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var aapsLogger: AAPSLogger
+ private lateinit var resultLauncherForResume: ActivityResultLauncher
+ private lateinit var resultLauncherForPause: ActivityResultLauncher
- private val disposable = CompositeDisposable()
+ private var disposable: CompositeDisposable = CompositeDisposable()
- private lateinit var refreshLoop: Runnable
- private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
+ override fun getLayoutId(): Int = R.layout.medtrum_overview_fragment
- private var _binding: MedtrumOverviewFragmentBinding? = null
-
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
- MedtrumOverviewFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
-
- @Synchronized
- override fun onResume() {
- super.onResume()
- disposable += rxBus
- .toObservable(EventMedtrumPumpUpdateGui::class.java)
- .observeOn(aapsSchedulers.main)
- .subscribe({ updateGui() }, fabricPrivacy::logException)
- disposable += rxBus
- .toObservable(EventTempBasalChange::class.java)
- .observeOn(aapsSchedulers.main)
- .subscribe({ updateGui() }, fabricPrivacy::logException)
- disposable += rxBus
- .toObservable(EventExtendedBolusChange::class.java)
- .observeOn(aapsSchedulers.main)
- .subscribe({ updateGui() }, fabricPrivacy::logException)
- refreshLoop = Runnable {
- activity?.runOnUiThread { updateGui() }
- handler.postDelayed(refreshLoop, T.mins(1).msecs())
- }
- handler.postDelayed(refreshLoop, T.mins(1).msecs())
- updateGui()
+ override fun onDestroy() {
+ super.onDestroy()
+ disposable.clear()
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.apply {
+ viewmodel = ViewModelProvider(this@MedtrumOverviewFragment, viewModelFactory).get(MedtrumOverviewViewModel::class.java)
+ viewmodel?.apply {
+ // TODO Handle events here, see eopatch eventhandler
+ }
+
+ resultLauncherForResume = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ when (it.resultCode) {
+ // TODO Handle events here, see eopatch eventhandler
+ }
+ }
+
+ resultLauncherForPause = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ when (it.resultCode) {
+ // TODO Handle events here, see eopatch eventhandler
+ }
+ }
+ }
}
- @Synchronized
override fun onPause() {
super.onPause()
- disposable.clear()
- handler.removeCallbacksAndMessages(null)
+ // TODO
}
- @Synchronized
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
+ override fun onResume() {
+ super.onResume()
+ // TODO
}
-
- @Synchronized
- private fun updateGui() {
- if (_binding == null) return
- val profile = profileFunction.getProfile() ?: return
- binding.baseBasalRate.text = rh.gs(info.nightscout.core.ui.R.string.pump_base_basal_rate, MedtrumPlugin.baseBasalRate)
- binding.tempbasal.text = iobCobCalculator.getTempBasal(dateUtil.now())?.toStringFull(profile, dateUtil)
- ?: ""
- binding.battery.text = rh.gs(info.nightscout.core.ui.R.string.format_percent, 0) // TODO
- binding.reservoir.text = rh.gs(info.nightscout.interfaces.R.string.format_insulin_units, 0.0) // TODO
-
- binding.serialNumber.text = MedtrumPlugin.serialNumber()
- }
-}
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
index 2ff064649f..c3b39693b3 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
@@ -1,12 +1,12 @@
package info.nightscout.pump.medtrum.ui.viewmodel
import androidx.lifecycle.ViewModel
-import info.nightscout.pump.medtrum.ui.BaseNavigator
+import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.disposables.Disposable
import java.lang.ref.WeakReference
-abstract class BaseViewModel : ViewModel() {
+abstract class BaseViewModel : ViewModel() {
private var _navigator: WeakReference? = null
var navigator: N?
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/OverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
similarity index 75%
rename from pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/OverviewViewModel.kt
rename to pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index c2288e5e23..0cce7e419c 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/OverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -1,19 +1,21 @@
package info.nightscout.pump.medtrum.ui.viewmodel
-import info.nightscout.pump.medtrum.ui.BaseNavigator
+import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import javax.inject.Inject
-class OverviewViewModel @Inject constructor(
+class MedtrumOverviewViewModel @Inject constructor(
private val aapsLogger: AAPSLogger
-) : BaseViewModel() {
+) : BaseViewModel() {
val isPatchActivated : Boolean
get() = false // TODO
val isPatchConnected: Boolean
get() = false // TODO
+ val bleStatus : String
+ get() ="" //TODO
init {
// TODO
diff --git a/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml b/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml
index f104a351de..471d939b6d 100644
--- a/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml
+++ b/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml
@@ -5,7 +5,7 @@
+ type="info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel"/>
-
+ android:fillViewport="true">
-
-
+ android:orientation="horizontal"
+ android:paddingTop="2dp"
+ android:paddingBottom="5dp"
+ android:visibility="gone">
-
-
-
-
-
+ android:layout_marginLeft="5dp"
+ android:layout_marginRight="5dp"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="@string/initializing"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ android:background="@color/list_delimiter" />
+ android:text="@string/medtrum_ble_status"
+ android:textSize="16sp" />
+ android:text="@string/colon"
+ android:textSize="16sp" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:text="@{viewmodel.bleStatus}"
+ android:textColor="@android:color/white"
+ android:textSize="16sp" />
@@ -286,8 +107,8 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/string_new_patch"
- android:enabled="@{!viewmodel.isPatchActivated}"/>
-
+ android:enabled="@{!viewmodel.isPatchActivated}"
+ app:onSafeClick="@{() -> viewmodel.onClickActivation()}"/>
-
+ android:enabled="@{viewmodel.isPatchActivated}"
+ app:onSafeClick="@{() -> viewmodel.onClickDeactivation()}"/>
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 36925f83d3..c6c5f1620b 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -4,12 +4,13 @@
snInput
medtrumpump_settings
-
Medtrum
MEDTRUM
Medtrum Nano
- MEDTRUM
Medtrum pump settings
+
+
+ BLE Status
SN
Serial number pump base
From 7afa0beb0a57a0c8584db8ab5f718b2c54009030 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 11 Mar 2023 20:19:06 +0100
Subject: [PATCH 011/116] Prepare patch step WIP
---
pump/medtrum/src/main/AndroidManifest.xml | 1 +
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 59 ++++----
.../nightscout/pump/medtrum/code/EventType.kt | 11 ++
.../nightscout/pump/medtrum/code/PatchStep.kt | 18 +++
.../pump/medtrum/di/MedtrumModule.kt | 28 +++-
.../extension/AppCompatActivityExtension.kt | 19 +++
.../pump/medtrum/services/BLEComm.kt | 9 +-
.../pump/medtrum/services/MedtrumService.kt | 85 ++++++++++--
.../pump/medtrum/ui/MedtrumActivity.kt | 97 +++++++++++++
.../medtrum/ui/MedtrumOverviewFragment.kt | 35 +++--
.../medtrum/ui/MedtrumPreparePatchFragment.kt | 42 ++++++
.../pump/medtrum/ui/MedtrumPrimeFragment.kt | 32 +++++
.../pump/medtrum/ui/event/SingleLiveEvent.kt | 29 ++++
.../pump/medtrum/ui/event/UIEvent.kt | 7 +
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 65 +++++++--
.../medtrum/ui/viewmodel/MedtrumViewModel.kt | 128 ++++++++++++++++++
.../src/main/res/layout/activity_medtrum.xml | 50 +++++++
...ment.xml => fragment_medtrum_overview.xml} | 12 +-
.../layout/fragment_medtrum_prepare_patch.xml | 66 +++++++++
.../res/layout/fragment_medtrum_prime.xml | 33 +++++
pump/medtrum/src/main/res/values/strings.xml | 12 +-
21 files changed, 750 insertions(+), 88 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/EventType.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/AppCompatActivityExtension.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/event/SingleLiveEvent.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/event/UIEvent.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
create mode 100644 pump/medtrum/src/main/res/layout/activity_medtrum.xml
rename pump/medtrum/src/main/res/layout/{medtrum_overview_fragment.xml => fragment_medtrum_overview.xml} (98%)
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_prepare_patch.xml
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_prime.xml
diff --git a/pump/medtrum/src/main/AndroidManifest.xml b/pump/medtrum/src/main/AndroidManifest.xml
index f589b49319..2e03434790 100644
--- a/pump/medtrum/src/main/AndroidManifest.xml
+++ b/pump/medtrum/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
- if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput))) {
- pumpSync.connectNewPump()
- changePump()
- }
- }, fabricPrivacy::logException)
- changePump()
}
override fun onStop() {
@@ -122,15 +111,8 @@ class MedtrumPlugin @Inject constructor(
}
}
- fun changePump() {
- aapsLogger.debug(LTag.PUMP, "changePump: called!")
- try {
- mDeviceSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
- } catch (e: NumberFormatException) {
- aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
- }
- // TODO: add medtrumPump.reset()
- commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.device_changed), null)
+ fun getService(): MedtrumService? {
+ return medtrumService
}
override fun isInitialized(): Boolean {
@@ -138,14 +120,17 @@ class MedtrumPlugin @Inject constructor(
}
override fun isSuspended(): Boolean {
- return false
+ return true
}
override fun isBusy(): Boolean {
- return false
+ return true
+ }
+
+ override fun isConnected(): Boolean {
+ return if (!isInitialized()) true else medtrumService?.isConnected ?: true // This is a workaround to prevent AAPS to trigger connects when we are initializing
}
- override fun isConnected(): Boolean = medtrumService?.isConnected ?: false
override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false
override fun isHandshakeInProgress(): Boolean = false
@@ -153,19 +138,23 @@ class MedtrumPlugin @Inject constructor(
}
override fun connect(reason: String) {
- aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
- aapsLogger.debug(LTag.PUMP, "Medtrum connect - service::$medtrumService")
- aapsLogger.debug(LTag.PUMP, "Medtrum connect - mDeviceSN:$mDeviceSN")
- if (medtrumService != null && mDeviceSN != 0.toLong()) {
- aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
- val success = medtrumService?.connect(reason, mDeviceSN) ?: false
- if (!success) ToastUtils.errorToast(context, info.nightscout.core.ui.R.string.ble_not_supported_or_not_paired)
+ if (isInitialized()) {
+ aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
+ aapsLogger.debug(LTag.PUMP, "Medtrum connect - service::$medtrumService")
+ // aapsLogger.debug(LTag.PUMP, "Medtrum connect - mDeviceSN:$mDeviceSN")
+ if (medtrumService != null) {
+ aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
+ val success = medtrumService?.connect(reason) ?: false
+ if (!success) ToastUtils.errorToast(context, info.nightscout.core.ui.R.string.ble_not_supported_or_not_paired)
+ }
}
}
override fun disconnect(reason: String) {
- aapsLogger.debug(LTag.PUMP, "RS disconnect from: $reason")
- medtrumService?.disconnect(reason)
+ if (isInitialized()) {
+ aapsLogger.debug(LTag.PUMP, "Medtrum disconnect from: $reason")
+ medtrumService?.disconnect(reason)
+ }
}
override fun stopConnecting() {
@@ -173,11 +162,13 @@ class MedtrumPlugin @Inject constructor(
}
override fun getPumpStatus(reason: String) {
- medtrumService?.readPumpStatus()
+ if (isInitialized()) {
+ medtrumService?.readPumpStatus()
+ }
}
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
- return PumpEnactResult(injector) // TODO
+ return PumpEnactResult(injector).success(true).enacted(true) // TODO
}
override fun isThisProfileSet(profile: Profile): Boolean {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/EventType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/EventType.kt
new file mode 100644
index 0000000000..32b4efb4ed
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/EventType.kt
@@ -0,0 +1,11 @@
+package info.nightscout.pump.medtrum.code
+
+enum class EventType {
+ ACTIVATION_CLICKED,
+ DEACTIVATION_CLICKED,
+ INVALID_BASAL_RATE,
+ PROFILE_NOT_SET,
+ FINISH_ACTIVITY,
+ SHOW_DISCARD_DIALOG
+ ;
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
new file mode 100644
index 0000000000..3b2c973ae6
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
@@ -0,0 +1,18 @@
+package info.nightscout.pump.medtrum.code
+
+enum class PatchStep {
+ SAFE_DEACTIVATION,
+ MANUALLY_TURNING_OFF_ALARM,
+ DISCARDED,
+ DISCARDED_FOR_CHANGE,
+ DISCARDED_FROM_ALARM,
+ PREPARE_PATCH,
+ PRIME,
+ ATTACH_INSERT_NEEDLE,
+ BASAL_SCHEDULE,
+ CHECK_CONNECTION,
+ CANCEL,
+ COMPLETE,
+ BACK_TO_HOME,
+ FINISH;
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
index 71af92437e..1666a4defe 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
@@ -7,17 +7,21 @@ import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoMap
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
import info.nightscout.pump.medtrum.services.MedtrumService
+import info.nightscout.pump.medtrum.ui.MedtrumActivity
import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
import info.nightscout.pump.medtrum.ui.viewmodel.ViewModelFactory
import info.nightscout.pump.medtrum.ui.viewmodel.ViewModelKey
import javax.inject.Provider
-
@Module
@Suppress("unused")
abstract class MedtrumModule {
+
companion object {
@Provides
@@ -34,11 +38,29 @@ abstract class MedtrumModule {
@ViewModelKey(MedtrumOverviewViewModel::class)
internal abstract fun bindsMedtrumOverviewViewmodel(viewModel: MedtrumOverviewViewModel): ViewModel
+ @Binds
+ @IntoMap
+ @MedtrumPluginQualifier
+ @ViewModelKey(MedtrumViewModel::class)
+ internal abstract fun bindsMedtrumViewModel(viewModel: MedtrumViewModel): ViewModel
+
// FRAGMENTS
@ContributesAndroidInjector
abstract fun contributesMedtrumOverviewFragment(): MedtrumOverviewFragment
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesPreparePatchFragment(): MedtrumPreparePatchFragment
+
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesPrimeFragment(): MedtrumPrimeFragment
+
+ // ACTIVITIES
+ @ContributesAndroidInjector
+ abstract fun contributesMedtrumActivity(): MedtrumActivity
+
// SERVICE
- @ContributesAndroidInjector
- abstract fun contributesDanaRSService(): MedtrumService
+ @ContributesAndroidInjector
+ abstract fun contributesMedtrumService(): MedtrumService
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/AppCompatActivityExtension.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/AppCompatActivityExtension.kt
new file mode 100644
index 0000000000..7345091cb4
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/AppCompatActivityExtension.kt
@@ -0,0 +1,19 @@
+package info.nightscout.pump.medtrum.extension
+
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentTransaction
+
+fun AppCompatActivity.replaceFragmentInActivity(fragment: Fragment, frameId: Int, addToBackStack: Boolean = false) {
+ supportFragmentManager.transact {
+ replace(frameId, fragment)
+ if (addToBackStack) addToBackStack(null)
+ }
+}
+
+private inline fun FragmentManager.transact(action: FragmentTransaction.() -> Unit) {
+ beginTransaction().apply {
+ action()
+ }.commit()
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index b6ad902279..fb71c5c388 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -49,7 +49,9 @@ import javax.inject.Inject
import javax.inject.Singleton
interface BLECommCallback {
+
fun onBLEConnected()
+ fun onBLEDisconnected()
fun onNotification(notification: ByteArray)
fun onIndication(indication: ByteArray)
fun onSendMessageError(reason: String)
@@ -88,8 +90,8 @@ class BLEComm @Inject internal constructor(
private val mBluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
private var mBluetoothGatt: BluetoothGatt? = null
- var isConnected = false
- var isConnecting = false
+ var isConnected = false // TODO: These may be removed have no function
+ var isConnecting = false// TODO: These may be removed have no function
private var uartWrite: BluetoothGattCharacteristic? = null
private var uartRead: BluetoothGattCharacteristic? = null
@@ -179,7 +181,6 @@ class BLEComm @Inject internal constructor(
}
aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
mBluetoothGatt?.disconnect()
- mBluetoothGatt = null
}
@Synchronized
@@ -373,7 +374,7 @@ class BLEComm @Inject internal constructor(
close()
isConnected = false
isConnecting = false
- rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
+ mCallback?.onBLEDisconnected()
aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index aa9fd7e552..7ff73f7a35 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -32,6 +32,7 @@ import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit
import info.nightscout.rx.events.EventInitializationChanged
import info.nightscout.rx.events.EventOverviewBolusProgress
+import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.events.EventProfileSwitchChanged
import info.nightscout.rx.events.EventPumpStatusChanged
import info.nightscout.rx.logging.AAPSLogger
@@ -79,6 +80,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
private var mDeviceSN: Long = 0
private var currentState: State = IdleState()
+ var isConnected = false
+ var isConnecting = false
// TODO: Stuff like this in a settings class?
private var mLastDeviceTime: Long = 0
@@ -90,6 +93,16 @@ class MedtrumService : DaggerService(), BLECommCallback {
.toObservable(EventAppExit::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ stopSelf() }, fabricPrivacy::logException)
+ disposable += rxBus
+ .toObservable(EventPreferenceChange::class.java)
+ .observeOn(aapsSchedulers.io)
+ .subscribe({ event ->
+ if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput))) {
+ pumpSync.connectNewPump()
+ changePump()
+ }
+ }, fabricPrivacy::logException)
+ changePump()
}
override fun onDestroy() {
@@ -97,26 +110,27 @@ class MedtrumService : DaggerService(), BLECommCallback {
super.onDestroy()
}
- val isConnected: Boolean
- get() = bleComm.isConnected
-
- val isConnecting: Boolean
- get() = bleComm.isConnecting
-
- fun connect(from: String, deviceSN: Long): Boolean {
- // TODO Check we might want to replace this with start scan?
- mDeviceSN = deviceSN
- return bleComm.connect(from, deviceSN)
+ fun connect(from: String): Boolean {
+ aapsLogger.debug(LTag.PUMP, "connect: called!")
+ if (currentState is IdleState) {
+ isConnecting = true
+ isConnected = false
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING))
+ return bleComm.connect(from, mDeviceSN)
+ } else {
+ aapsLogger.error(LTag.PUMPCOMM, "Connect attempt when in non Idle state from: " + from)
+ return false
+ }
}
fun stopConnecting() {
// TODO proper way for this might need send commands etc
- // bleComm.stopConnecting()
+ bleComm.stopConnecting()
}
fun disconnect(from: String) {
// TODO proper way for this might need send commands etc
- // bleComm.disconnect(from)
+ bleComm.disconnect(from)
}
fun readPumpStatus() {
@@ -156,11 +170,30 @@ class MedtrumService : DaggerService(), BLECommCallback {
return false
}
+ fun changePump() {
+ aapsLogger.debug(LTag.PUMP, "changePump: called!")
+ try {
+ mDeviceSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
+ } catch (e: NumberFormatException) {
+ aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
+ }
+ // TODO: What do we do with active patch here?
+ when (currentState) {
+ // is IdleState -> connect("changePump")
+ // is ReadyState -> disconnect("changePump")
+ else -> null // TODO: What to do here? Abort stuff?
+ }
+ }
+
/** BLECommCallbacks */
override fun onBLEConnected() {
currentState.onConnected()
}
+ override fun onBLEDisconnected() {
+ currentState.onDisconnected()
+ }
+
override fun onNotification(notification: ByteArray) {
aapsLogger.debug(LTag.PUMPCOMM, "<<<<< onNotification" + notification.contentToString())
// TODO
@@ -207,14 +240,34 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.debug(LTag.PUMPCOMM, "onIndicationr: " + this.toString() + "Should not be called here!")
}
- open fun onConnected() {}
+ open fun onConnected() {
+ aapsLogger.debug(LTag.PUMPCOMM, "onConnected")
+ }
+
+ open fun onDisconnected() {
+ aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected")
+ isConnecting = false
+ isConnected = false
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
+
+ // TODO: Check flow for this
+ toState(IdleState())
+ }
}
private inner class IdleState : State() {
+ override fun onEnter() {}
+
override fun onConnected() {
+ super.onConnected()
toState(AuthState())
}
+
+ override fun onDisconnected() {
+ super.onDisconnected()
+ // TODO replace this by proper connecting state where we can retry
+ }
}
private inner class AuthState : State() {
@@ -391,7 +444,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!")
+ // Now we are fully connected and authenticated and we can start sending commands. Let AAPS know
+ isConnecting = false
+ isConnected = true
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
}
// Just a placeholder, this state is reached when the patch is ready to receive commands (Bolus, temp basal and whatever)
}
-}
\ No newline at end of file
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
new file mode 100644
index 0000000000..7b49049a6e
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
@@ -0,0 +1,97 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.app.Dialog
+import android.content.Context
+import android.content.Intent
+import android.media.MediaPlayer
+import android.media.RingtoneManager
+import android.os.Bundle
+import android.view.MotionEvent
+import androidx.appcompat.app.AlertDialog
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
+import info.nightscout.core.utils.extensions.safeGetSerializableExtra
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.ActivityMedtrumBinding
+import info.nightscout.pump.medtrum.extension.replaceFragmentInActivity
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+
+class MedtrumActivity : MedtrumBaseActivity() {
+
+ override fun getLayoutId(): Int = R.layout.activity_medtrum
+
+ override fun dispatchTouchEvent(event: MotionEvent): Boolean {
+ if (event.actionMasked == MotionEvent.ACTION_UP) {
+ // TODO
+ }
+
+ return super.dispatchTouchEvent(event)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ binding.apply {
+ viewModel = ViewModelProvider(this@MedtrumActivity, viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ processIntent(intent)
+
+ patchStep.observe(this@MedtrumActivity) {
+ when (it) {
+ PatchStep.PREPARE_PATCH -> setupViewFragment(MedtrumPreparePatchFragment.newInstance())
+ PatchStep.PRIME -> setupViewFragment(MedtrumPrimeFragment.newInstance())
+ PatchStep.CANCEL -> this@MedtrumActivity.finish()
+ else -> Unit
+ }
+ }
+ }
+ }
+ }
+
+ override fun onNewIntent(intent: Intent?) {
+ super.onNewIntent(intent)
+ processIntent(intent)
+ }
+
+ private fun processIntent(intent: Intent?) {
+ binding.viewModel?.apply {
+ intent?.run {
+ val step = intent.safeGetSerializableExtra(EXTRA_START_PATCH_STEP, PatchStep::class.java)
+ initializePatchStep(step)
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ // TODO
+ }
+
+ override fun onBackPressed() {
+ binding.viewModel?.apply {
+ // TODO DEACTIVATION ?
+ }
+ }
+
+ companion object {
+
+ const val EXTRA_START_PATCH_STEP = "EXTRA_START_PATCH_FRAGMENT_UI"
+ const val EXTRA_START_FROM_MENU = "EXTRA_START_FROM_MENU"
+
+ @JvmStatic
+ fun createIntentFromMenu(context: Context, patchStep: PatchStep): Intent {
+ return Intent(context, MedtrumActivity::class.java).apply {
+ putExtra(EXTRA_START_PATCH_STEP, patchStep)
+ putExtra(EXTRA_START_FROM_MENU, true)
+ }
+ }
+
+ }
+
+ private fun setupViewFragment(baseFragment: MedtrumBaseFragment<*>) {
+ replaceFragmentInActivity(baseFragment, R.id.framelayout_fragment, false)
+ }
+
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index a29b8c60ad..25aad5ce89 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -6,18 +6,18 @@ import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.ViewModelProvider
-import info.nightscout.pump.medtrum.databinding.MedtrumOverviewFragmentBinding
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumOverviewBinding
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.EventType
+import info.nightscout.pump.medtrum.code.PatchStep
import info.nightscout.rx.AapsSchedulers
-import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import io.reactivex.rxjava3.disposables.CompositeDisposable
import javax.inject.Inject
-class MedtrumOverviewFragment : MedtrumBaseFragment() {
+class MedtrumOverviewFragment : MedtrumBaseFragment() {
- @Inject lateinit var rxBus: RxBus
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var aapsLogger: AAPSLogger
private lateinit var resultLauncherForResume: ActivityResultLauncher
@@ -25,7 +25,7 @@ class MedtrumOverviewFragment : MedtrumBaseFragment
+ when (evt.peekContent()) {
+ EventType.ACTIVATION_CLICKED -> requireContext().apply { startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.PREPARE_PATCH)) }
+ else -> Unit
+ }
}
- }
- resultLauncherForPause = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
- when (it.resultCode) {
- // TODO Handle events here, see eopatch eventhandler
+ resultLauncherForResume = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ when (it.resultCode) {
+ // TODO Handle events here, see eopatch eventhandler
+ }
+ }
+
+ resultLauncherForPause = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ when (it.resultCode) {
+ // TODO Handle events here, see eopatch eventhandler
+ }
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
new file mode 100644
index 0000000000..650d103f6e
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
@@ -0,0 +1,42 @@
+package info.nightscout.androidaps.plugins.pump.eopatch.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPreparePatchBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumPreparePatchFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumPreparePatchFragment = MedtrumPreparePatchFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_prepare_patch
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ aapsLogger.debug(LTag.PUMP, "MedtrumPreparePatchFragment onViewCreated")
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ // TODO: Confirmation dialog
+ MedtrumViewModel.SetupStep.CONNECTED -> btnPositive.visibility = View.VISIBLE
+ else -> Unit
+ }
+ }
+ preparePatch()
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
new file mode 100644
index 0000000000..42f27d3105
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
@@ -0,0 +1,32 @@
+package info.nightscout.androidaps.plugins.pump.eopatch.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPrimeBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumPrimeFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumPrimeFragment = MedtrumPrimeFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_prime
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ // TODO do stuff
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/event/SingleLiveEvent.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/event/SingleLiveEvent.kt
new file mode 100644
index 0000000000..2d52d4d7cd
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/event/SingleLiveEvent.kt
@@ -0,0 +1,29 @@
+package info.nightscout.pump.medtrum.ui.event
+
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Observer
+import androidx.annotation.MainThread
+import java.util.concurrent.atomic.AtomicBoolean
+
+open class SingleLiveEvent : MutableLiveData() {
+ private val mPending = AtomicBoolean(false)
+ override fun observe(owner: LifecycleOwner, observer: Observer) {
+ super.observe(owner) { t ->
+ if (mPending.compareAndSet(true, false)) {
+ observer.onChanged(t)
+ }
+ }
+ }
+
+ @MainThread
+ override fun setValue(t: T?) {
+ mPending.set(true)
+ super.setValue(t)
+ }
+
+ @MainThread
+ fun call() {
+ value = null
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/event/UIEvent.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/event/UIEvent.kt
new file mode 100644
index 0000000000..e1f879799b
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/event/UIEvent.kt
@@ -0,0 +1,7 @@
+package info.nightscout.pump.medtrum.ui.event
+
+open class UIEvent(private val content: T) {
+ var value: Any? = null
+ fun peekContent(): T = content
+}
+
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index 0cce7e419c..d270275c03 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -1,32 +1,77 @@
package info.nightscout.pump.medtrum.ui.viewmodel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.pump.medtrum.code.EventType
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
+import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
+import info.nightscout.pump.medtrum.ui.event.UIEvent
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
+import info.nightscout.interfaces.profile.ProfileFunction
+import info.nightscout.rx.AapsSchedulers
+import info.nightscout.rx.bus.RxBus
+import info.nightscout.rx.events.EventPumpStatusChanged
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
+import io.reactivex.rxjava3.disposables.CompositeDisposable
+import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject
class MedtrumOverviewViewModel @Inject constructor(
- private val aapsLogger: AAPSLogger
+ private val aapsLogger: AAPSLogger,
+ private val rxBus: RxBus,
+ private val aapsSchedulers: AapsSchedulers,
+ private val fabricPrivacy: FabricPrivacy,
+ private val profileFunction: ProfileFunction,
) : BaseViewModel() {
- val isPatchActivated : Boolean
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ private val _eventHandler = SingleLiveEvent>()
+ val eventHandler: LiveData>
+ get() = _eventHandler
+
+ private val _bleStatus = SingleLiveEvent()
+ val bleStatus: LiveData
+ get() = _bleStatus
+
+ // TODO make these livedata
+ val isPatchActivated: Boolean
get() = false // TODO
- val isPatchConnected: Boolean
- get() = false // TODO
- val bleStatus : String
- get() ="" //TODO
init {
- // TODO
+ disposable += rxBus
+ .toObservable(EventPumpStatusChanged::class.java)
+ .observeOn(aapsSchedulers.main)
+ .subscribe({
+ _bleStatus.value = when (it.status) {
+ EventPumpStatusChanged.Status.CONNECTING ->
+ "{fa-bluetooth-b spin} ${it.secondsElapsed}s"
+
+ EventPumpStatusChanged.Status.CONNECTED ->
+ "{fa-bluetooth}"
+
+ EventPumpStatusChanged.Status.DISCONNECTED ->
+ "{fa-bluetooth-b}"
+
+ else ->
+ ""
+ }
+ }, fabricPrivacy::logException)
}
- fun onClickActivation(){
+ fun onClickActivation() {
aapsLogger.debug(LTag.PUMP, "Start Patch clicked!")
- // TODO
+ val profile = profileFunction.getProfile()
+ if (profile == null) {
+ _eventHandler.postValue(UIEvent(EventType.PROFILE_NOT_SET))
+ } else {
+ _eventHandler.postValue(UIEvent(EventType.ACTIVATION_CLICKED))
+ }
}
- fun onClickDeactivation(){
+ fun onClickDeactivation() {
aapsLogger.debug(LTag.PUMP, "Stop Patch clicked!")
// TODO
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
new file mode 100644
index 0000000000..328b42a89a
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
@@ -0,0 +1,128 @@
+package info.nightscout.pump.medtrum.ui.viewmodel
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.pump.medtrum.MedtrumPlugin
+import info.nightscout.pump.medtrum.services.MedtrumService
+import info.nightscout.pump.medtrum.code.EventType
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
+import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
+import info.nightscout.pump.medtrum.ui.event.UIEvent
+import info.nightscout.shared.interfaces.ResourceHelper
+import info.nightscout.rx.AapsSchedulers
+import info.nightscout.rx.bus.RxBus
+import info.nightscout.rx.events.EventPumpStatusChanged
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.sharedPreferences.SP
+import io.reactivex.rxjava3.disposables.CompositeDisposable
+import io.reactivex.rxjava3.kotlin.plusAssign
+import javax.inject.Inject
+
+class MedtrumViewModel @Inject constructor(
+ private val rh: ResourceHelper,
+ private val aapsLogger: AAPSLogger,
+ private val rxBus: RxBus,
+ private val aapsSchedulers: AapsSchedulers,
+ private val fabricPrivacy: FabricPrivacy,
+ private val medtrumPlugin: MedtrumPlugin,
+ private val sp: SP
+) : BaseViewModel() {
+
+ val patchStep = MutableLiveData()
+
+ val title = "Activation"
+
+ val medtrumService: MedtrumService?
+ get() = medtrumPlugin.getService()
+
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ private val _eventHandler = SingleLiveEvent>()
+ val eventHandler: LiveData>
+ get() = _eventHandler
+
+ private var mInitPatchStep: PatchStep? = null
+
+ init {
+ disposable += rxBus
+ .toObservable(EventPumpStatusChanged::class.java)
+ .observeOn(aapsSchedulers.main)
+ .subscribe({
+ when (it.status) {
+ EventPumpStatusChanged.Status.CONNECTING -> {}
+
+ EventPumpStatusChanged.Status.CONNECTED
+ -> if (patchStep.value == PatchStep.PREPARE_PATCH) setupStep.postValue(SetupStep.CONNECTED) else {
+ }
+
+ EventPumpStatusChanged.Status.DISCONNECTED -> {}
+
+ else -> {}
+ }
+ }, fabricPrivacy::logException)
+ }
+
+ fun moveStep(newPatchStep: PatchStep) {
+ val oldPatchStep = patchStep.value
+
+ if (oldPatchStep != newPatchStep) {
+ when (newPatchStep) {
+ PatchStep.CANCEL -> {
+ if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Cancel") else {
+ }
+ }
+
+ else -> null
+ }?.let {
+ // TODO Update lifecycle
+ }
+ }
+
+ prepareStep(newPatchStep)
+
+ aapsLogger.info(LTag.PUMP, "moveStep: $oldPatchStep -> $newPatchStep")
+ }
+
+ fun initializePatchStep(step: PatchStep?) {
+ mInitPatchStep = prepareStep(step)
+ }
+
+ fun preparePatch() {
+ // TODO: Decide if we want to connect already when user is still filling, or if we want to wait after user is done filling
+ medtrumService?.connect("PreparePatch")
+ }
+
+ private fun prepareStep(step: PatchStep?): PatchStep {
+ // TODO Title per screen :) And proper sync with patchstate
+ // (step ?: convertToPatchStep(patchConfig.lifecycleEvent.lifeCycle)).let { newStep ->
+
+ (step ?: PatchStep.SAFE_DEACTIVATION).let { newStep ->
+ when (newStep) {
+
+ else -> ""
+ }.let {
+
+ }
+
+ patchStep.postValue(newStep)
+
+ return newStep
+ }
+ }
+
+ enum class SetupStep {
+ CONNECTED,
+ PRIME_READY,
+ ACTIVATED
+ }
+
+ val setupStep = MutableLiveData()
+
+ private fun updateSetupStep(newSetupStep: SetupStep) {
+ aapsLogger.info(LTag.PUMP, "curSetupStep: ${setupStep.value}, newSetupStep: $newSetupStep")
+ setupStep.postValue(newSetupStep)
+ }
+}
diff --git a/pump/medtrum/src/main/res/layout/activity_medtrum.xml b/pump/medtrum/src/main/res/layout/activity_medtrum.xml
new file mode 100644
index 0000000000..c7658e2ce9
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/activity_medtrum.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
similarity index 98%
rename from pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml
rename to pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index 471d939b6d..b7b6cdedfe 100644
--- a/pump/medtrum/src/main/res/layout/medtrum_overview_fragment.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -3,9 +3,10 @@
xmlns:tools="http://schemas.android.com/tools">
+
+ type="info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel" />
+
+ android:text="@string/string_new_patch"
+ app:onSafeClick="@{() -> viewmodel.onClickActivation()}" />
+ android:text="@string/string_stop_patch"
+ app:onSafeClick="@{() -> viewmodel.onClickDeactivation()}" />
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_prepare_patch.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_prepare_patch.xml
new file mode 100644
index 0000000000..b03f5e0446
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_prepare_patch.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_prime.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_prime.xml
new file mode 100644
index 0000000000..cbdb2073e1
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_prime.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index c6c5f1620b..9ea34ecd97 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -11,10 +11,16 @@
BLE Status
-
- SN
- Serial number pump base
Start new patch
Stop patch
+
+ Discard/Change Patch
+ Start priming
+
+
+ SN
+ Serial number pump base
+
+
From 90392b2452c2912a89b471cdf01fa0d54903161a Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 18 Mar 2023 17:58:19 +0100
Subject: [PATCH 012/116] Packet classes
---
.../res/layout/fragment_eopatch_overview.xml | 2 +-
pump/medtrum/build.gradle | 3 +
.../pump/medtrum/comm/WriteCommand.kt | 61 ----------
.../medtrum/comm/packets/ActivatePacket.kt | 25 ++++
.../medtrum/comm/packets/AuthorizePacket.kt | 47 +++++++
.../medtrum/comm/packets/CancelBolusPacket.kt | 16 +++
.../comm/packets/CancelTempBasalPacket.kt | 19 +++
.../pump/medtrum/comm/packets/CommandType.kt | 23 ++++
.../comm/packets/GetDeviceTypePacket.kt | 35 ++++++
.../medtrum/comm/packets/GetTimePacket.kt | 30 +++++
.../medtrum/comm/packets/MedtrumPacket.kt | 73 +++++++++++
.../medtrum/comm/packets/PollPatchPacket.kt | 11 ++
.../pump/medtrum/comm/packets/PrimePacket.kt | 11 ++
.../comm/packets/ReadBolusStatePacket.kt | 29 +++++
.../comm/packets/SetBasalProfilePacket.kt | 16 +++
.../comm/packets/SetBolusMotorPacket.kt | 17 +++
.../medtrum/comm/packets/SetBolusPacket.kt | 16 +++
.../medtrum/comm/packets/SetPatchPacket.kt | 17 +++
.../comm/packets/SetTempBasalPacket.kt | 25 ++++
.../medtrum/comm/packets/SetTimePacket.kt | 18 +++
.../medtrum/comm/packets/SetTimeZonePacket.kt | 24 ++++
.../medtrum/comm/packets/StopPatchPacket.kt | 19 +++
.../medtrum/comm/packets/SubscribePacket.kt | 17 +++
.../medtrum/comm/packets/SynchronizePacket.kt | 37 ++++++
.../pump/medtrum/di/MedtrumCommModule.kt | 49 ++++++++
.../pump/medtrum/di/MedtrumModule.kt | 4 +-
.../pump/medtrum/services/BLEComm.kt | 3 +
.../pump/medtrum/services/MedtrumService.kt | 113 +++++++----------
.../res/layout/fragment_medtrum_overview.xml | 2 +-
.../androidaps/ProfileStoreObject.kt | 107 ++++++++++++++++
.../info/nightscout/androidaps/TestBase.kt | 1 +
.../androidaps/TestBaseWithProfile.kt | 59 +++++++++
.../pump/medtrum/MedtrumTestBase.kt | 7 ++
.../comm/packets/ActivatePacketTest.kt | 33 +++++
.../comm/packets/AuthorizePacketTest.kt | 76 ++++++++++++
.../comm/packets/CancelBolusPacketTest.kt | 33 +++++
.../comm/packets/CancelTempBasalPacketTest.kt | 33 +++++
.../comm/packets/GetDeviceTypePacketTest.kt | 73 +++++++++++
.../medtrum/comm/packets/GetTimePacketTest.kt | 68 +++++++++++
.../medtrum/comm/packets/MedtrumPacketTest.kt | 115 ++++++++++++++++++
.../comm/packets/PollPatchPacketTest.kt | 33 +++++
.../medtrum/comm/packets/PrimePacketTest.kt | 33 +++++
.../comm/packets/ReadBolusStatePacketTest.kt | 54 ++++++++
.../comm/packets/SetBasalProfilePacketTest.kt | 33 +++++
.../comm/packets/SetBolusMotorPacketTest.kt | 34 ++++++
.../comm/packets/SetBolusPacketTest.kt | 34 ++++++
.../comm/packets/SetPatchPacketTest.kt | 34 ++++++
.../comm/packets/SetTempBasalPacketTest.kt | 62 ++++++++++
.../medtrum/comm/packets/SetTimePacketTest.kt | 37 ++++++
.../comm/packets/SetTimeZonePacketTest.kt | 41 +++++++
.../comm/packets/StopPatchPacketTest.kt | 35 ++++++
.../comm/packets/SubscribePacketTest.kt | 35 ++++++
.../comm/packets/SynchronizePacketTest.kt | 72 +++++++++++
53 files changed, 1771 insertions(+), 133 deletions(-)
delete mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommand.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CommandType.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PrimePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/androidaps/ProfileStoreObject.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/PrimePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
diff --git a/pump/eopatch/src/main/res/layout/fragment_eopatch_overview.xml b/pump/eopatch/src/main/res/layout/fragment_eopatch_overview.xml
index c05e793ac2..47adbaf3a0 100644
--- a/pump/eopatch/src/main/res/layout/fragment_eopatch_overview.xml
+++ b/pump/eopatch/src/main/res/layout/fragment_eopatch_overview.xml
@@ -73,7 +73,7 @@
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
- android:text="@string/colon"
+ android:text=":"
android:textSize="16sp" />
data.size) {
+ failed = true
+ aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected response length, expected: $expectedMinRespLength got: ${data.size}")
+ return false
+ }
+
+ val incomingOpCode: Byte = data.copyOfRange(RESP_OPCODE_START, RESP_OPCODE_END).first()
+ val responseCode = data.copyOfRange(RESP_RESULT_START, RESP_RESULT_END).toInt()
+
+ return when {
+ incomingOpCode != opCode -> {
+ failed = true
+ aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected command, expected: $opCode got: $incomingOpCode")
+ false
+ }
+
+ responseCode == 0 -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Happy command: $opCode response: $responseCode")
+ true
+ }
+
+ responseCode == RESP_WAITING -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Waiting command: $opCode response: $responseCode")
+ // Waiting do nothing
+ false
+ }
+
+ else -> {
+ failed = true
+ aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Error in command: $opCode response: $responseCode")
+ false
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacket.kt
new file mode 100644
index 0000000000..561d28d5aa
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacket.kt
@@ -0,0 +1,11 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.POLL_PATCH
+
+class PollPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = POLL_PATCH.code
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PrimePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PrimePacket.kt
new file mode 100644
index 0000000000..ceafc7ea67
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PrimePacket.kt
@@ -0,0 +1,11 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.PRIME
+
+class PrimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = PRIME.code
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
new file mode 100644
index 0000000000..dfd10abfef
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
@@ -0,0 +1,29 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.READ_BOLUS_STATE
+import info.nightscout.pump.medtrum.extension.toInt
+
+class ReadBolusStatePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ var bolusData: ByteArray = byteArrayOf()
+
+ companion object {
+
+ private const val RESP_BOLUS_DATA_START = 6 // TODO: check this
+ }
+
+ init {
+ opCode = READ_BOLUS_STATE.code
+ expectedMinRespLength = RESP_BOLUS_DATA_START + 1
+ }
+
+ override fun handleResponse(data: ByteArray): Boolean {
+ val success = super.handleResponse(data)
+ if (success) {
+ bolusData = data.copyOfRange(RESP_BOLUS_DATA_START, data.size)
+ }
+
+ return success
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
new file mode 100644
index 0000000000..133d1fec54
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
@@ -0,0 +1,16 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_BASAL_PROFILE
+
+class SetBasalProfilePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = SET_BASAL_PROFILE.code
+ }
+
+ override fun getRequest(): ByteArray {
+ // TODO get basal profile settings
+ return byteArrayOf(opCode)
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
new file mode 100644
index 0000000000..d048075bf2
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
@@ -0,0 +1,17 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_BOLUS_MOTOR
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+
+class SetBolusMotorPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = SET_BOLUS_MOTOR.code
+ }
+
+ override fun getRequest(): ByteArray {
+ return byteArrayOf(opCode) + 0.toByte()
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacket.kt
new file mode 100644
index 0000000000..776ac4ba2c
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacket.kt
@@ -0,0 +1,16 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_BOLUS
+
+class SetBolusPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = SET_BOLUS.code
+ }
+
+ override fun getRequest(): ByteArray {
+ // TODO get bolus settings
+ return byteArrayOf(opCode) + 0.toByte()
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
new file mode 100644
index 0000000000..b434d790f4
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
@@ -0,0 +1,17 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_PATCH
+import info.nightscout.pump.medtrum.extension.toByteArray
+
+class SetPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = SET_PATCH.code
+ }
+
+ override fun getRequest(): ByteArray {
+ // TODO get patch settings
+ return byteArrayOf(opCode)
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
new file mode 100644
index 0000000000..366e9c76de
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
@@ -0,0 +1,25 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_TEMP_BASAL
+
+class SetTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = SET_TEMP_BASAL.code
+ // TODO set expectedMinRespLength
+ }
+
+ override fun getRequest(): ByteArray {
+ // TODO get temp basal settings
+ return byteArrayOf(opCode)
+ }
+
+ override fun handleResponse(data: ByteArray): Boolean {
+ val success = super.handleResponse(data)
+ if (success) {
+ // TODO Save basal
+ }
+ return success
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacket.kt
new file mode 100644
index 0000000000..a2defdeb9a
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacket.kt
@@ -0,0 +1,18 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_TIME
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+
+class SetTimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = SET_TIME.code
+ }
+
+ override fun getRequest(): ByteArray {
+ val time = MedtrumTimeUtil().getCurrentTimePumpSeconds()
+ return byteArrayOf(opCode) + 2.toByte() + time.toByteArray(4)
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacket.kt
new file mode 100644
index 0000000000..2a1828167a
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacket.kt
@@ -0,0 +1,24 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_TIME_ZONE
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import info.nightscout.shared.utils.DateUtil
+import javax.inject.Inject
+
+class SetTimeZonePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ @Inject lateinit var dateUtil: DateUtil
+
+ init {
+ opCode = SET_TIME_ZONE.code
+ }
+
+ override fun getRequest(): ByteArray {
+ val time = MedtrumTimeUtil().getCurrentTimePumpSeconds()
+ var offsetMins = dateUtil.getTimeZoneOffsetMinutes(dateUtil.now())
+ if (offsetMins < 0) offsetMins += 65536
+ return byteArrayOf(opCode) + offsetMins.toByteArray(2) + time.toByteArray(4)
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
new file mode 100644
index 0000000000..c037c10839
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
@@ -0,0 +1,19 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.STOP_PATCH
+
+class StopPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = STOP_PATCH.code
+ }
+
+ override fun handleResponse(data: ByteArray): Boolean {
+ val success = super.handleResponse(data)
+ if (success) {
+ // TODO
+ }
+ return success
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacket.kt
new file mode 100644
index 0000000000..37a2b6e1be
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacket.kt
@@ -0,0 +1,17 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SUBSCRIBE
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+
+class SubscribePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = SUBSCRIBE.code
+ }
+
+ override fun getRequest(): ByteArray {
+ return byteArrayOf(opCode) + 4095.toByteArray(2)
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
new file mode 100644
index 0000000000..a600013c74
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
@@ -0,0 +1,37 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.CommandType.SYNCHRONIZE
+import info.nightscout.pump.medtrum.extension.toInt
+
+class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ var state: Int = 0
+ var dataFieldsPresent: Int = 0
+ var syncData: ByteArray = byteArrayOf()
+
+ companion object {
+
+ private const val RESP_STATE_START = 6
+ private const val RESP_STATE_END = RESP_STATE_START + 1
+ private const val RESP_FIELDS_START = 7
+ private const val RESP_FIELDS_END = RESP_FIELDS_START + 2
+ private const val RESP_SYNC_DATA_START = 9
+ }
+
+ init {
+ opCode = SYNCHRONIZE.code
+ expectedMinRespLength = RESP_SYNC_DATA_START + 1
+ }
+
+ override fun handleResponse(data: ByteArray): Boolean {
+ val success = super.handleResponse(data)
+ if (success) {
+ state = data.copyOfRange(RESP_STATE_START, RESP_STATE_END).toInt()
+ dataFieldsPresent = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
+ syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)
+ }
+
+ return success
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
new file mode 100644
index 0000000000..893030c6c2
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
@@ -0,0 +1,49 @@
+package info.nightscout.pump.medtrum.di
+
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import info.nightscout.pump.medtrum.comm.packets.ActivatePacket
+import info.nightscout.pump.medtrum.comm.packets.AuthorizePacket
+import info.nightscout.pump.medtrum.comm.packets.CancelBolusPacket
+import info.nightscout.pump.medtrum.comm.packets.CancelTempBasalPacket
+import info.nightscout.pump.medtrum.comm.packets.GetDeviceTypePacket
+import info.nightscout.pump.medtrum.comm.packets.GetTimePacket
+import info.nightscout.pump.medtrum.comm.packets.MedtrumPacket
+import info.nightscout.pump.medtrum.comm.packets.PollPatchPacket
+import info.nightscout.pump.medtrum.comm.packets.PrimePacket
+import info.nightscout.pump.medtrum.comm.packets.ReadBolusStatePacket
+import info.nightscout.pump.medtrum.comm.packets.SetBasalProfilePacket
+import info.nightscout.pump.medtrum.comm.packets.SetBolusMotorPacket
+import info.nightscout.pump.medtrum.comm.packets.SetBolusPacket
+import info.nightscout.pump.medtrum.comm.packets.SetPatchPacket
+import info.nightscout.pump.medtrum.comm.packets.SetTempBasalPacket
+import info.nightscout.pump.medtrum.comm.packets.SetTimePacket
+import info.nightscout.pump.medtrum.comm.packets.SetTimeZonePacket
+import info.nightscout.pump.medtrum.comm.packets.StopPatchPacket
+import info.nightscout.pump.medtrum.comm.packets.SubscribePacket
+import info.nightscout.pump.medtrum.comm.packets.SynchronizePacket
+
+@Module
+abstract class MedtrumCommModule {
+
+ @ContributesAndroidInjector abstract fun contributesActivatePacket(): ActivatePacket
+ @ContributesAndroidInjector abstract fun contributesAuthorizePacket(): AuthorizePacket
+ @ContributesAndroidInjector abstract fun contributesCancelBolusPacket(): CancelBolusPacket
+ @ContributesAndroidInjector abstract fun contributesCancelTempBasalPacket(): CancelTempBasalPacket
+ @ContributesAndroidInjector abstract fun contributesGetDeviceTypePacket(): GetDeviceTypePacket
+ @ContributesAndroidInjector abstract fun contributesGetTimePacket(): GetTimePacket
+ @ContributesAndroidInjector abstract fun contributesMedtrumPacket(): MedtrumPacket
+ @ContributesAndroidInjector abstract fun contributesPollPatchPacket(): PollPatchPacket
+ @ContributesAndroidInjector abstract fun contributesPrimePacket(): PrimePacket
+ @ContributesAndroidInjector abstract fun contributesReadBolusStatePacket(): ReadBolusStatePacket
+ @ContributesAndroidInjector abstract fun contributesSetBasalProfilePacket(): SetBasalProfilePacket
+ @ContributesAndroidInjector abstract fun contributesSetBolusMotorPacket(): SetBolusMotorPacket
+ @ContributesAndroidInjector abstract fun contributesSetBolusPacket(): SetBolusPacket
+ @ContributesAndroidInjector abstract fun contributesSetPatchPacket(): SetPatchPacket
+ @ContributesAndroidInjector abstract fun contributesSetTempBasalPacket(): SetTempBasalPacket
+ @ContributesAndroidInjector abstract fun contributesSetTimePacket(): SetTimePacket
+ @ContributesAndroidInjector abstract fun contributesSetTimeZonePacket(): SetTimeZonePacket
+ @ContributesAndroidInjector abstract fun contributesStopPatchPacket(): StopPatchPacket
+ @ContributesAndroidInjector abstract fun contributesSubscribePacket(): SubscribePacket
+ @ContributesAndroidInjector abstract fun contributesSynchronizePacket(): SynchronizePacket
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
index 1666a4defe..18f4fb7419 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
@@ -18,7 +18,7 @@ import info.nightscout.pump.medtrum.ui.viewmodel.ViewModelFactory
import info.nightscout.pump.medtrum.ui.viewmodel.ViewModelKey
import javax.inject.Provider
-@Module
+@Module(includes = [MedtrumCommModule::class])
@Suppress("unused")
abstract class MedtrumModule {
@@ -63,4 +63,4 @@ abstract class MedtrumModule {
// SERVICE
@ContributesAndroidInjector
abstract fun contributesMedtrumService(): MedtrumService
-}
\ No newline at end of file
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index fb71c5c388..f1b6e1e280 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -180,6 +180,9 @@ class BLEComm @Inject internal constructor(
return
}
aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
+ if (isConnecting) {
+ stopScan()
+ }
mBluetoothGatt?.disconnect()
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 7ff73f7a35..faea212261 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -5,52 +5,38 @@ import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.IBinder
-import android.os.SystemClock
import dagger.android.DaggerService
import dagger.android.HasAndroidInjector
import info.nightscout.core.utils.fabric.FabricPrivacy
-import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.constraints.Constraints
-import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
-import info.nightscout.interfaces.pump.BolusProgressData
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.pump.PumpSync
-import info.nightscout.interfaces.queue.Callback
-import info.nightscout.interfaces.queue.Command
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.medtrum.MedtrumPlugin
-import info.nightscout.pump.medtrum.comm.WriteCommand
+import info.nightscout.pump.medtrum.comm.packets.*
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit
-import info.nightscout.rx.events.EventInitializationChanged
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.events.EventPreferenceChange
-import info.nightscout.rx.events.EventProfileSwitchChanged
import info.nightscout.rx.events.EventPumpStatusChanged
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
-import info.nightscout.shared.utils.T
-import io.reactivex.rxjava3.core.ObservableEmitter
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
-import org.joda.time.DateTime
-import org.joda.time.DateTimeZone
import java.util.*
-import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.math.abs
-import kotlin.math.min
class MedtrumService : DaggerService(), BLECommCallback {
@@ -71,7 +57,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var pumpSync: PumpSync
@Inject lateinit var dateUtil: DateUtil
- @Inject lateinit var writeCommand: WriteCommand
val timeUtil = MedtrumTimeUtil()
@@ -80,6 +65,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
private var mDeviceSN: Long = 0
private var currentState: State = IdleState()
+ private var mPacket: MedtrumPacket? = null
var isConnected = false
var isConnecting = false
@@ -118,7 +104,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING))
return bleComm.connect(from, mDeviceSN)
} else {
- aapsLogger.error(LTag.PUMPCOMM, "Connect attempt when in non Idle state from: " + from)
+ aapsLogger.error(LTag.PUMPCOMM, "Connect attempt when in non Idle state from: $from")
return false
}
}
@@ -205,7 +191,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
override fun onSendMessageError(reason: String) {
- aapsLogger.debug(LTag.PUMPCOMM, "<<<<< error during send message " + reason)
+ aapsLogger.debug(LTag.PUMPCOMM, "<<<<< error during send message $reason")
// TODO
}
@@ -237,7 +223,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
open fun onEnter() {}
open fun onIndication(data: ByteArray) {
- aapsLogger.debug(LTag.PUMPCOMM, "onIndicationr: " + this.toString() + "Should not be called here!")
+ aapsLogger.debug(LTag.PUMPCOMM, "onIndication: " + this.toString() + "Should not be called here!")
}
open fun onConnected() {
@@ -274,18 +260,19 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached AuthState")
- bleComm.sendMessage(writeCommand.authorize(mDeviceSN))
+ mPacket = AuthorizePacket(injector, mDeviceSN)
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
}
override fun onIndication(data: ByteArray) {
- // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
- val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
- val responseCode = data.copyOfRange(4, 6).toInt()
- // TODO Get pump version info (do we care?)
- if (responseCode == 0 && commandCode == writeCommand.COMMAND_AUTH_REQ) {
+ if (mPacket?.handleResponse(data) == true) {
// Succes!
+ // TODO Get pump version info
+ val deviceType = (mPacket as AuthorizePacket).deviceType
+ val swVersion = (mPacket as AuthorizePacket).swVersion
+ aapsLogger.debug(LTag.PUMPCOMM, "GetDeviceTypeState: deviceType: $deviceType swVersion: $swVersion") // TODO remove me later
toState(GetDeviceTypeState())
- } else {
+ } else if (mPacket?.failed == true) {
// Failure
bleComm.disconnect("Failure")
toState(IdleState())
@@ -297,18 +284,19 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached GetDeviceTypeState")
- bleComm.sendMessage(writeCommand.getDeviceType())
+ mPacket = GetDeviceTypePacket(injector)
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
}
override fun onIndication(data: ByteArray) {
- // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
- val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
- val responseCode = data.copyOfRange(4, 6).toInt()
- // TODO Get device type (do we care?)
- if (responseCode == 0 && commandCode == writeCommand.COMMAND_GET_DEVICE_TYPE) {
+ if (mPacket?.handleResponse(data) == true) {
// Succes!
+ // TODO Get device type and SN
+ val deviceType = (mPacket as GetDeviceTypePacket).deviceType
+ val deviceSN = (mPacket as GetDeviceTypePacket).deviceSN
+ aapsLogger.debug(LTag.PUMPCOMM, "GetDeviceTypeState: deviceType: $deviceType deviceSN: $deviceSN") // TODO remove me later
toState(GetTimeState())
- } else {
+ } else if (mPacket?.failed == true) {
// Failure
bleComm.disconnect("Failure")
toState(IdleState())
@@ -320,30 +308,27 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached GetTimeState")
- bleComm.sendMessage(writeCommand.getTime())
+ mPacket = GetTimePacket(injector)
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
}
override fun onIndication(data: ByteArray) {
- // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
- val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
- val responseCode = data.copyOfRange(4, 6).toInt()
- val time = data.copyOfRange(6, 10).toLong()
- if (responseCode == 0 && commandCode == writeCommand.COMMAND_GET_TIME) {
+ if (mPacket?.handleResponse(data) == true) {
// Succes!
- mLastDeviceTime = time
+ mLastDeviceTime = (mPacket as GetTimePacket).time
val currTimeSec = dateUtil.nowWithoutMilliseconds() / 1000
- if (abs(timeUtil.convertPumpTimeToSystemTimeSeconds(time) - currTimeSec) <= 5) { // Allow 5 sec deviation
+ if (abs(timeUtil.convertPumpTimeToSystemTimeSeconds(mLastDeviceTime) - currTimeSec) <= 5) { // Allow 5 sec deviation
toState(SynchronizeState())
} else {
aapsLogger.debug(
LTag.PUMPCOMM,
- "GetTimeState.onIndication need to set time. systemTime: " + currTimeSec + " PumpTime: " + time + " Pump Time to system time: " + timeUtil.convertPumpTimeToSystemTimeSeconds(
- time
+ "GetTimeState.onIndication need to set time. systemTime: $currTimeSec PumpTime: $mLastDeviceTime Pump Time to system time: " + timeUtil.convertPumpTimeToSystemTimeSeconds(
+ mLastDeviceTime
)
)
toState(SetTimeState())
}
- } else {
+ } else if (mPacket?.failed == true) {
// Failure
bleComm.disconnect("Failure")
toState(IdleState())
@@ -355,17 +340,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SetTimeState")
- bleComm.sendMessage(writeCommand.setTime())
+ mPacket = SetTimePacket(injector)
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
}
override fun onIndication(data: ByteArray) {
- // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
- val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
- val responseCode = data.copyOfRange(4, 6).toInt()
- if (responseCode == 0 && commandCode == writeCommand.COMMAND_SET_TIME) {
+ if (mPacket?.handleResponse(data) == true) {
// Succes!
toState(SetTimeZoneState())
- } else {
+ } else if (mPacket?.failed == true) {
// Failure
bleComm.disconnect("Failure")
toState(IdleState())
@@ -377,17 +360,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SetTimeZoneState")
- bleComm.sendMessage(writeCommand.setTimeZone())
+ mPacket = SetTimeZonePacket(injector)
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
}
override fun onIndication(data: ByteArray) {
- // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
- val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
- val responseCode = data.copyOfRange(4, 6).toInt()
- if (responseCode == 0 && commandCode == writeCommand.COMMAND_SET_TIME_ZONE) {
+ if (mPacket?.handleResponse(data) == true) {
// Succes!
toState(SynchronizeState())
- } else {
+ } else if (mPacket?.failed == true) {
// Failure
bleComm.disconnect("Failure")
toState(IdleState())
@@ -399,18 +380,16 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SynchronizeState")
- bleComm.sendMessage(writeCommand.synchronize())
+ mPacket = SynchronizePacket(injector)
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
}
override fun onIndication(data: ByteArray) {
- // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
- val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
- val responseCode = data.copyOfRange(4, 6).toInt()
- if (responseCode == 0 && commandCode == writeCommand.COMMAND_SYNCHRONIZE) {
+ if (mPacket?.handleResponse(data) == true) {
// Succes!
// TODO: Handle pump state parameters
toState(SubscribeState())
- } else {
+ } else if (mPacket?.failed == true) {
// Failure
bleComm.disconnect("Failure")
toState(IdleState())
@@ -422,17 +401,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SubscribeState")
- bleComm.sendMessage(writeCommand.subscribe())
+ mPacket = SubscribePacket(injector)
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
}
override fun onIndication(data: ByteArray) {
- // TODO Create class for this? Maybe combine with authorize write command, something like danaRS packets? + Unit Tests
- val commandCode: Byte = data.copyOfRange(1, 2).toInt().toByte()
- val responseCode = data.copyOfRange(4, 6).toInt()
- if (responseCode == 0 && commandCode == writeCommand.COMMAND_SUBSCRIBE) {
+ if (mPacket?.handleResponse(data) == true) {
// Succes!
toState(ReadyState())
- } else {
+ } else if (mPacket?.failed == true) {
// Failure
bleComm.disconnect("Failure")
toState(IdleState())
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index b7b6cdedfe..68c7073fad 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -74,7 +74,7 @@
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
- android:text="@string/colon"
+ android:text=":"
android:textSize="16sp" />
()
+
+ private fun storeUnits(): String? = JsonHelper.safeGetStringAllowNull(data, "units", null)
+
+ private fun getStore(): JSONObject? {
+ try {
+ if (data.has("store")) return data.getJSONObject("store")
+ } catch (e: JSONException) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ return null
+ }
+
+ override fun getStartDate(): Long {
+ val iso = JsonHelper.safeGetString(data, "startDate") ?: return 0
+ return try {
+ dateUtil.fromISODateString(iso)
+ } catch (e: Exception) {
+ 0
+ }
+ }
+
+ override fun getDefaultProfile(): PureProfile? = getDefaultProfileName()?.let { getSpecificProfile(it) }
+ override fun getDefaultProfileJson(): JSONObject? = getDefaultProfileName()?.let { getSpecificProfileJson(it) }
+
+ override fun getDefaultProfileName(): String? {
+ val defaultProfileName = data.optString("defaultProfile")
+ return if (defaultProfileName.isNotEmpty()) getStore()?.has(defaultProfileName)?.let { defaultProfileName } else null
+ }
+
+ override fun getProfileList(): ArrayList {
+ val ret = ArrayList()
+ getStore()?.keys()?.let { keys ->
+ while (keys.hasNext()) {
+ val profileName = keys.next() as String
+ ret.add(profileName)
+ }
+ }
+ return ret
+ }
+
+ @Synchronized
+ override fun getSpecificProfile(profileName: String): PureProfile? {
+ var profile: PureProfile? = null
+ val units = JsonHelper.safeGetStringAllowNull(data, "units", storeUnits())
+ getStore()?.let { store ->
+ if (store.has(profileName)) {
+ profile = cachedObjects[profileName]
+ if (profile == null) {
+ JsonHelper.safeGetJSONObject(store, profileName, null)?.let { profileObject ->
+ profile = pureProfileFromJson(profileObject, dateUtil, units)
+ profile?.let { cachedObjects[profileName] = profile }
+ }
+ }
+ }
+ }
+ return profile
+ }
+
+ private fun getSpecificProfileJson(profileName: String): JSONObject? {
+ getStore()?.let { store ->
+ if (store.has(profileName))
+ return JsonHelper.safeGetJSONObject(store, profileName, null)
+ }
+ return null
+ }
+
+ override val allProfilesValid: Boolean
+ get() = getProfileList()
+ .asSequence()
+ .map { profileName -> getSpecificProfile(profileName.toString()) }
+ .map { pureProfile -> pureProfile?.let { ProfileSealed.Pure(pureProfile).isValid("allProfilesValid", activePlugin.activePump, config, rh, rxBus, hardLimits, false) } }
+ .all { it?.isValid == true }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
index 96af831f2b..67aa52703d 100644
--- a/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBase.kt
@@ -11,6 +11,7 @@ import org.mockito.junit.jupiter.MockitoSettings
import org.mockito.quality.Strictness
import java.util.Locale
+@Suppress("SpellCheckingInspection")
@ExtendWith(MockitoExtension::class)
@MockitoSettings(strictness = Strictness.LENIENT)
open class TestBase {
diff --git a/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt
new file mode 100644
index 0000000000..529aebf36d
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt
@@ -0,0 +1,59 @@
+package info.nightscout.androidaps
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.core.extensions.pureProfileFromJson
+import info.nightscout.core.profile.ProfileSealed
+import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.interfaces.Config
+import info.nightscout.interfaces.plugin.ActivePlugin
+import info.nightscout.interfaces.profile.DefaultValueHelper
+import info.nightscout.interfaces.profile.Profile
+import info.nightscout.interfaces.profile.ProfileFunction
+import info.nightscout.interfaces.profile.ProfileStore
+import info.nightscout.rx.bus.RxBus
+import info.nightscout.shared.interfaces.ResourceHelper
+import info.nightscout.shared.utils.DateUtil
+import org.json.JSONObject
+import org.junit.jupiter.api.BeforeEach
+import org.mockito.Mock
+
+@Suppress("SpellCheckingInspection")
+open class TestBaseWithProfile : TestBase() {
+
+ @Mock lateinit var activePluginProvider: ActivePlugin
+ @Mock lateinit var rh: ResourceHelper
+ @Mock lateinit var fabricPrivacy: FabricPrivacy
+ @Mock lateinit var profileFunction: ProfileFunction
+ @Mock lateinit var defaultValueHelper: DefaultValueHelper
+ @Mock lateinit var dateUtil: DateUtil
+ @Mock lateinit var config: Config
+
+ val rxBus = RxBus(aapsSchedulers, aapsLogger)
+
+ val profileInjector = HasAndroidInjector {
+ AndroidInjector {
+ }
+ }
+
+ private lateinit var validProfileJSON: String
+ lateinit var validProfile: Profile
+ @Suppress("PropertyName") val TESTPROFILENAME = "someProfile"
+
+ @BeforeEach
+ fun prepareMock() {
+ validProfileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
+ "{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
+ "\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
+ validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!)
+ }
+
+ fun getValidProfileStore(): ProfileStore {
+ val json = JSONObject()
+ val store = JSONObject()
+ store.put(TESTPROFILENAME, JSONObject(validProfileJSON))
+ json.put("defaultProfile", TESTPROFILENAME)
+ json.put("store", store)
+ return ProfileStoreObject(profileInjector, json, dateUtil)
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
new file mode 100644
index 0000000000..e1d6419c59
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
@@ -0,0 +1,7 @@
+package info.nightscout.pump.medtrum
+
+import info.nightscout.androidaps.TestBaseWithProfile
+
+open class MedtrumTestBase: TestBaseWithProfile() {
+
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
new file mode 100644
index 0000000000..282f2c24da
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
@@ -0,0 +1,33 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class ActivatePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 18
+
+ // Call
+ val packet = ActivatePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
new file mode 100644
index 0000000000..294670f0fe
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
@@ -0,0 +1,76 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class AuthorizePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketAndSNWhenCalledThenReturnAuthorizePacket() {
+ // Inputs
+ val opCode = 5
+ val sn = 2859923929
+
+ // Call
+ val packet = AuthorizePacket(packetInjector, sn)
+ val result = packet.getRequest()
+
+ // Expected values
+ val key = 3364239851
+ val type = 2
+ val expectedByteArray = byteArrayOf(opCode.toByte()) + type.toByte() + 0.toByteArray(4) + key.toByteArray(4)
+ assertEquals(10, result.size)
+ assertEquals(expectedByteArray.contentToString(), result.contentToString())
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageIsCorrectLengthThenResultTrue() {
+ // Inputs
+ val opCode = 5
+ val responseCode = 0
+ val deviceType = 80
+ val swVerX = 12
+ val swVerY = 1
+ val swVerZ = 3
+
+ // Call
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + 0.toByte() + deviceType.toByte() + swVerX.toByte() + swVerY.toByte() + swVerZ.toByte()
+ val packet = AuthorizePacket(packetInjector, 0)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ val swString = "$swVerX.$swVerY.$swVerZ"
+ assertEquals(true, result)
+ assertEquals(false, packet.failed)
+ assertEquals(deviceType, packet.deviceType)
+ assertEquals(swString, packet.swVersion)
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val opCode = 5
+ val responseCode = 0
+
+ // Call
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2)
+ val packet = AuthorizePacket(packetInjector, 0)
+ packet.opCode = opCode.toByte()
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacketTest.kt
new file mode 100644
index 0000000000..94a63e3022
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacketTest.kt
@@ -0,0 +1,33 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class CancelBolusPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 20
+
+ // Call
+ val packet = CancelBolusPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
new file mode 100644
index 0000000000..3bfc30ef4b
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
@@ -0,0 +1,33 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class CancelTempBasalPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 25
+
+ // Call
+ val packet = CancelTempBasalPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacketTest.kt
new file mode 100644
index 0000000000..73663e4ee0
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacketTest.kt
@@ -0,0 +1,73 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class GetDeviceTypePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 6
+
+ // Call
+ val packet = GetDeviceTypePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageIsCorrectLengthThenResultTrue() {
+ // Inputs
+ val opCode = 6
+ val responseCode = 0
+ val deviceType = 80
+ val deviceSN: Long = 12345678
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + deviceType.toByte() + deviceSN.toByteArray(4)
+
+ // Call
+ val packet = GetDeviceTypePacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(true, result)
+ assertEquals(false, packet.failed)
+ assertEquals(deviceType, packet.deviceType)
+ assertEquals(deviceSN, packet.deviceSN)
+
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val opCode = 6
+ val responseCode = 0
+ val deviceType = 80
+ val deviceSN: Long = 12345678
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + deviceType.toByte() + deviceSN.toByteArray(4)
+
+ // Call
+ val packet = GetDeviceTypePacket(packetInjector)
+ val result = packet.handleResponse(response.sliceArray(0..response.size - 2))
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
+ assertEquals(0, packet.deviceType)
+ assertEquals(0, packet.deviceSN)
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
new file mode 100644
index 0000000000..4ea715a677
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
@@ -0,0 +1,68 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class GetTimePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 11
+
+ // Call
+ val packet = GetTimePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageIsCorrectLengthThenResultTrue() {
+ // Inputs
+ val opCode = 11
+ val responseCode = 0
+ val time: Long = 1234567890
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + time.toByteArray(4)
+
+ // Call
+ val packet = GetTimePacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(true, result)
+ assertEquals(false, packet.failed)
+ assertEquals(time, packet.time)
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val opCode = 11
+ val responseCode = 0
+ val time: Long = 1234567890
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + time.toByteArray(4)
+
+ // Call
+ val packet = GetTimePacket(packetInjector)
+ val result = packet.handleResponse(response.sliceArray(0..response.size - 2))
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
+ assertEquals(0, packet.time)
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacketTest.kt
new file mode 100644
index 0000000000..33fb7ff2b1
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacketTest.kt
@@ -0,0 +1,115 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class MedtrumPacketTest : MedtrumTestBase() {
+
+ /** Test base behavoir of the medtrum packet, thse */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 1
+
+ // Call
+ val packet = MedtrumPacket(packetInjector)
+ packet.opCode = opCode.toByte()
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(result.size, 1)
+ assertEquals(result[0], opCode.toByte())
+ }
+
+ @Test fun handleResponseGivenResponseWhenOpcodeIsCorrectThenResultTrue() {
+ // Inputs
+ val opCode = 1
+ val responseCode = 0
+ val response = byteArrayOf(0) + opCode.toByte() + 0x0 + 0x0 + responseCode.toByteArray(2)
+
+ // Call
+ val packet = MedtrumPacket(packetInjector)
+ packet.opCode = opCode.toByte()
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(result, true)
+ assertEquals(packet.failed, false)
+ }
+
+ @Test fun handleResponseGivenRepsonseWhenOpcodeIsIncorrectThenResultFalse() {
+ // Inputs
+ val opCode = 1
+ val responseCode = 0
+ val response = byteArrayOf(0) + (opCode + 1).toByte() + 0x0 + 0x0 + responseCode.toByteArray(2)
+
+ // Call
+ val packet = MedtrumPacket(packetInjector)
+ packet.opCode = opCode.toByte()
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(result, false)
+ assertEquals(packet.failed, true)
+ }
+
+ @Test fun handleResponseGivenResponseWhenResponseCodeIsWaitingThenResultFalse() {
+ // Inputs
+ val opCode = 1
+ val responseCode = 16384
+ val response = byteArrayOf(0) + opCode.toByte() + 0x0 + 0x0 + responseCode.toByteArray(2)
+
+ // Call
+ val packet = MedtrumPacket(packetInjector)
+ packet.opCode = opCode.toByte()
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(result, false)
+ assertEquals(packet.failed, false)
+ }
+
+ @Test fun handleResponseGivenResponseWhenRepsonseCodeIsErrorThenResultFalse() {
+ // Inputs
+ val opCode = 1
+ val responseCode = 1
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2)
+
+ // Call
+ val packet = MedtrumPacket(packetInjector)
+ packet.opCode = opCode.toByte()
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val opCode = 1
+ val responseCode = 0
+ val response = byteArrayOf(0) + opCode.toByte() + 0x0 + 0x0
+
+ // Call
+ val packet = MedtrumPacket(packetInjector)
+ packet.opCode = opCode.toByte()
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacketTest.kt
new file mode 100644
index 0000000000..1763c59f10
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacketTest.kt
@@ -0,0 +1,33 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class PollPatchPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 30
+
+ // Call
+ val packet = PollPatchPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/PrimePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/PrimePacketTest.kt
new file mode 100644
index 0000000000..b1b941540b
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/PrimePacketTest.kt
@@ -0,0 +1,33 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class PrimePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 16
+
+ // Call
+ val packet = PrimePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacketTest.kt
new file mode 100644
index 0000000000..05bb898792
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacketTest.kt
@@ -0,0 +1,54 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class ReadBolusStatePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageIsCorrectLengthThenResultTrue() {
+ // Inputs
+ val opCode = 34
+ val responseCode = 0
+ val bolusData = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + bolusData
+
+ // Call
+ val packet = ReadBolusStatePacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(true, result)
+ assertEquals(false, packet.failed)
+ assertEquals(bolusData.contentToString(), packet.bolusData.contentToString())
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val opCode = 34
+ val responseCode = 0
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2)
+
+ // Call
+ val packet = ReadBolusStatePacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
+ assertEquals(byteArrayOf().contentToString(), packet.bolusData.contentToString())
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
new file mode 100644
index 0000000000..e257795771
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
@@ -0,0 +1,33 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SetBasalProfilePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 21
+
+ // Call
+ val packet = SetBasalProfilePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacketTest.kt
new file mode 100644
index 0000000000..f07e501c37
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacketTest.kt
@@ -0,0 +1,34 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SetBolusMotorPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 36
+
+ // Call
+ val packet = SetBolusMotorPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ val expectedByteArray = byteArrayOf(opCode.toByte()) + 0.toByte()
+ assertEquals(2, result.size)
+ assertEquals(expectedByteArray.contentToString(), result.contentToString())
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacketTest.kt
new file mode 100644
index 0000000000..6d4f5413c3
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacketTest.kt
@@ -0,0 +1,34 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SetBolusPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 19
+
+ // Call
+ val packet = SetBolusPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ // TODO correct value's
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
new file mode 100644
index 0000000000..7e360909eb
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
@@ -0,0 +1,34 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SetPatchPacket : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 35
+
+ // Call
+ val packet = SetBolusPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ // TODO correct value's
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
new file mode 100644
index 0000000000..5643aa5c9b
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
@@ -0,0 +1,62 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SetTempBasalPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 24
+
+ // Call
+ val packet = SetTempBasalPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCodeAndDuration() {
+ // TODO
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCodeAndDurationAndRate() {
+ // TODO
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageIsCorrectLengthThenResultTrue() {
+ // TODO
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val opCode = 24
+ val responseCode = 0
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2)
+
+ // Call
+ val packet = ReadBolusStatePacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
+ // assertEquals(byteArrayOf().contentToString(), packet.bolusData.contentToString()) TODO
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacketTest.kt
new file mode 100644
index 0000000000..08fba5ae89
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacketTest.kt
@@ -0,0 +1,37 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SetTimePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 10
+ val time = MedtrumTimeUtil().getCurrentTimePumpSeconds() // TODO: Mock time proper?
+
+ // Call
+ val packet = SetTimePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ val expectedByteArray = byteArrayOf(opCode.toByte()) + 2.toByte() + time.toByteArray(4)
+ assertEquals(6, result.size)
+ assertEquals(expectedByteArray.contentToString(), result.contentToString())
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacketTest.kt
new file mode 100644
index 0000000000..cf2d858ee0
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacketTest.kt
@@ -0,0 +1,41 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SetTimeZonePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ if (it is SetTimeZonePacket) {
+ it.dateUtil = dateUtil
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 12
+ val time = MedtrumTimeUtil().getCurrentTimePumpSeconds() // TODO: Mock time proper?
+ val offsetMins = dateUtil.getTimeZoneOffsetMinutes(dateUtil.now()) // TODO: Mock time proper?
+
+ // Call
+ val packet = SetTimeZonePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ val expectedByteArray = byteArrayOf(opCode.toByte()) + offsetMins.toByteArray(2) + time.toByteArray(4)
+ assertEquals(7, result.size)
+ assertEquals(expectedByteArray.contentToString(), result.contentToString())
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
new file mode 100644
index 0000000000..53ffcfe9d0
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
@@ -0,0 +1,35 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class StopPatchPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 31
+
+ // Call
+ val packet = StopPatchPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+
+ // TODO: Add tests for the response
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacketTest.kt
new file mode 100644
index 0000000000..5f50ff2bf3
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacketTest.kt
@@ -0,0 +1,35 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SubscribePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 4
+
+ // Call
+ val packet = SubscribePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ val expectedByteArray = byteArrayOf(opCode.toByte()) + 4095.toByteArray(2)
+ assertEquals(3, result.size)
+ assertEquals(expectedByteArray.contentToString(), result.contentToString())
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
new file mode 100644
index 0000000000..121f51b3a6
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
@@ -0,0 +1,72 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class SynchronizePacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 3
+
+ // Call
+ val packet = SynchronizePacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageIsCorrectLengthThenResultTrue() {
+ // Inputs
+ val opCode = 3
+ val responseCode = 0
+ val state = 1
+ val dataFieldsPresent = 4046
+ val syncData = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + state.toByteArray(1) + dataFieldsPresent.toByteArray(2) + syncData
+
+ // Call
+ val packet = SynchronizePacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(true, result)
+ assertEquals(false, packet.failed)
+ assertEquals(state, packet.state)
+ assertEquals(dataFieldsPresent, packet.dataFieldsPresent)
+ assertEquals(syncData.contentToString(), packet.syncData.contentToString())
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val opCode = 3
+ val responseCode = 0
+ val state = 1
+ val dataFieldsPresent = 4046
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + state.toByteArray(1) + dataFieldsPresent.toByteArray(2)
+
+ // Call
+ val packet = SynchronizePacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
+ }
+}
From db409f5b7f00f4b99f5b24168a920277e12a31fd Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Fri, 24 Mar 2023 19:36:58 +0100
Subject: [PATCH 013/116] Packet implementation
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 109 ++++++++++++++
.../pump/medtrum/comm/enums/AlarmSetting.kt | 12 ++
.../comm/{packets => enums}/CommandType.kt | 2 +-
.../medtrum/comm/enums/MedtrumPumpState.kt | 29 ++++
.../medtrum/comm/packets/ActivatePacket.kt | 75 +++++++++-
.../medtrum/comm/packets/AuthorizePacket.kt | 2 +-
.../medtrum/comm/packets/CancelBolusPacket.kt | 10 +-
.../comm/packets/CancelTempBasalPacket.kt | 32 ++++-
.../comm/packets/GetDeviceTypePacket.kt | 2 +-
.../medtrum/comm/packets/GetTimePacket.kt | 2 +-
.../medtrum/comm/packets/PollPatchPacket.kt | 2 +-
.../pump/medtrum/comm/packets/PrimePacket.kt | 2 +-
.../comm/packets/ReadBolusStatePacket.kt | 5 +-
.../comm/packets/SetBasalProfilePacket.kt | 12 +-
.../comm/packets/SetBolusMotorPacket.kt | 4 +-
.../medtrum/comm/packets/SetBolusPacket.kt | 15 +-
.../medtrum/comm/packets/SetPatchPacket.kt | 29 +++-
.../comm/packets/SetTempBasalPacket.kt | 49 ++++++-
.../medtrum/comm/packets/SetTimePacket.kt | 2 +-
.../medtrum/comm/packets/SetTimeZonePacket.kt | 2 +-
.../medtrum/comm/packets/StopPatchPacket.kt | 21 ++-
.../medtrum/comm/packets/SubscribePacket.kt | 3 +-
.../medtrum/comm/packets/SynchronizePacket.kt | 2 +-
.../pump/medtrum/extension/BoolExtension.kt | 8 ++
.../pump/medtrum/util/MedtrumTimeUtil.kt | 6 +-
.../androidaps/TestBaseWithProfile.kt | 136 ++++++++++++++++--
.../pump/medtrum/MedtrumPumpTest.kt | 52 +++++++
.../pump/medtrum/MedtrumTestBase.kt | 19 ++-
.../comm/packets/ActivatePacketTest.kt | 65 ++++++++-
.../comm/packets/AuthorizePacketTest.kt | 8 +-
.../comm/packets/CancelBolusPacketTest.kt | 5 +-
.../comm/packets/CancelTempBasalPacketTest.kt | 39 ++++-
.../comm/packets/ReadBolusStatePacketTest.kt | 6 +-
.../comm/packets/SetBasalProfilePacketTest.kt | 10 +-
.../comm/packets/SetBolusPacketTest.kt | 9 +-
.../comm/packets/SetPatchPacketTest.kt | 20 +--
.../comm/packets/SetTempBasalPacketTest.kt | 58 +++++---
.../medtrum/comm/packets/SetTimePacketTest.kt | 2 +-
.../comm/packets/SetTimeZonePacketTest.kt | 4 +-
.../comm/packets/StopPatchPacketTest.kt | 31 +++-
40 files changed, 781 insertions(+), 120 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/AlarmSetting.kt
rename pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/{packets => enums}/CommandType.kt (89%)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/BoolExtension.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
new file mode 100644
index 0000000000..0435ff973c
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -0,0 +1,109 @@
+package info.nightscout.pump.medtrum
+
+import info.nightscout.interfaces.Constants
+import info.nightscout.interfaces.profile.Instantiator
+import info.nightscout.interfaces.profile.Profile
+import info.nightscout.interfaces.profile.ProfileStore
+import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.pump.defs.PumpType
+import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.sharedPreferences.SP
+import info.nightscout.shared.utils.DateUtil
+import info.nightscout.shared.utils.T
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.math.round
+
+@Singleton
+class MedtrumPump @Inject constructor(
+ private val aapsLogger: AAPSLogger,
+ private val sp: SP,
+ private val dateUtil: DateUtil,
+ private val instantiator: Instantiator
+) {
+
+ enum class PatchActivationState(val state: Int) {
+ NONE(0),
+ IDLE(1),
+ ACTIVATING(2),
+ ACTIVATED(3),
+ DEACTIVATING(4),
+ DEACTIVATED(5),
+ ERROR(6)
+ }
+
+ // Pump state and parameters
+ var pumpState = MedtrumPumpState.NONE // TODO save in SP
+ var patchActivationState = PatchActivationState.NONE // TODO save in SP
+
+ // TODO set these setting on init
+ // User settings (desired values, to be set on pump)
+ var desiredPatchExpiration = false
+ var desiredAlarmSetting = AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code
+ var desiredHourlyMaxInsulin: Int = 40
+ var desiredDailyMaxInsulin: Int = 180
+
+ // User settings (actual value's as reported by pump)
+
+ // Alarm settings
+
+ // Pump status
+
+ var patchId = 0L
+ var lastTimeReceivedFromPump = 0L // Time in seconds!
+
+ // Pump history
+
+ // Last basal status update
+ var lastBasalType = 0
+ var lastBasalRate = 0.0
+ var lastBasalSequence = 0
+ var lastBasalPatchId = 0
+ var lastBasalStartTime = 0L
+
+ // Last stop status update
+ var lastStopSequence = 0
+ var lastStopPatchId = 0
+
+ fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
+ val list = nsProfile.getBasalValues()
+ var basals = byteArrayOf()
+ for (item in list) {
+ val rate = round(item.value / 0.05).toInt()
+ val time = item.timeAsSeconds / 60
+ if (rate > 0xFFF || time > 0xFFF) {
+ aapsLogger.error(LTag.PUMP, "buildMedtrumProfileArray: rate or time too large: $rate, $time")
+ return null
+ }
+ basals += ((rate shl 12) + time).toByteArray(3)
+ aapsLogger.debug(LTag.PUMP, "buildMedtrumProfileArray: value: ${item.value} time: ${item.timeAsSeconds}")
+ }
+ return (list.size).toByteArray(1) + basals
+ }
+
+ fun handleBasalStatusUpdate(basalType: Int, basalValue: Double, basalSequence: Int, basalPatchId: Int, basalStartTime: Long) {
+ handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now())
+ }
+
+ fun handleBasalStatusUpdate(basalType: Int, basalRate: Double, basalSequence: Int, basalPatchId: Int, basalStartTime: Long, receivedTime: Long) {
+ aapsLogger.debug(
+ LTag.PUMP, "handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " +
+ "receivedTime: $receivedTime"
+ )
+ lastBasalType = basalType
+ lastBasalRate = basalRate
+ lastBasalSequence = basalSequence
+ lastBasalPatchId = basalPatchId
+ lastBasalStartTime = basalStartTime
+ }
+
+ fun handleStopStatusUpdate(stopSequence: Int, stopPatchId: Int) {
+ aapsLogger.debug(LTag.PUMP, "handleStopStatusUpdate: stopSequence: $stopSequence stopPatchId: $stopPatchId")
+ lastStopSequence = stopSequence
+ lastStopPatchId = stopPatchId
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/AlarmSetting.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/AlarmSetting.kt
new file mode 100644
index 0000000000..83557b4ff3
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/AlarmSetting.kt
@@ -0,0 +1,12 @@
+package info.nightscout.pump.medtrum.comm.enums
+
+enum class AlarmSetting(val code: Byte) {
+ LIGHT_VIBRATE_AND_BEEP(0),
+ LIGHT_AND_VIBRATE(1),
+ LIGHT_AND_BEEP(2),
+ LIGHT_ONLY(3),
+ VIBRATE_AND_BEEP(4),
+ VIBRATE_ONLY(5),
+ BEEP_ONLY(6),
+ NONE(7)
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CommandType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
similarity index 89%
rename from pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CommandType.kt
rename to pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
index 12118a1422..8b6119c0b4 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CommandType.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
@@ -1,4 +1,4 @@
-package info.nightscout.pump.medtrum.comm.packets
+package info.nightscout.pump.medtrum.comm.enums
enum class CommandType(val code: Byte) {
SYNCHRONIZE(3),
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
new file mode 100644
index 0000000000..eabfcac976
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
@@ -0,0 +1,29 @@
+package info.nightscout.pump.medtrum.comm.enums
+
+enum class MedtrumPumpState(val state: Byte) {
+ NONE(0),
+ IDLE(1),
+ DELIVERING(2),
+ PRIMING(3),
+ PRIMED(4),
+ EJECTING(5),
+ EJECTED(6),
+ ACTIVE(32),
+ ACTIVE_ALT(33),
+ LOWBG_SUSPENDED(64),
+ LOWBG_SUSPENDED2(65),
+ AUTO_SUSPENDED(66),
+ HMAX_SUSPENDED(67),
+ DMAX_SUSPENDED(68),
+ SUSPENDED(69),
+ PAUSED(70),
+ OCCLUSION(96),
+ EXPIRED(97),
+ RESERVOIR_EMPTY(98),
+ PATCH_FAULT(99),
+ PATCH_FAULT2(100),
+ BASE_FAULT(101),
+ BATTERY_OUT(102),
+ NO_CALIBRATION(103),
+ STOPPED(128.toByte())
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
index 994314058b..3e53670032 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
@@ -1,23 +1,88 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.ACTIVATE
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.CommandType.ACTIVATE
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.extension.toByte
+import info.nightscout.interfaces.stats.TddCalculator
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.extension.toLong
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import javax.inject.Inject
+import kotlin.math.round
-class ActivatePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: ByteArray) : MedtrumPacket(injector) {
+
+ @Inject lateinit var medtrumPump: MedtrumPump
+ @Inject lateinit var tddCalculator: TddCalculator
+
+ companion object {
+
+ private const val RESP_PATCH_ID_START = 6
+ private const val RESP_PATCH_ID_END = RESP_PATCH_ID_START + 4
+ private const val RESP_TIME_START = 10
+ private const val RESP_TIME_END = RESP_TIME_START + 4
+ private const val RESP_BASAL_TYPE_START = 14
+ private const val RESP_BASAL_TYPE_END = RESP_BASAL_TYPE_START + 1
+ private const val RESP_BASAL_VALUE_START = 15
+ private const val RESP_BASAL_VALUE_END = RESP_BASAL_VALUE_START + 2
+ private const val RESP_BASAL_SEQUENCE_START = 17
+ private const val RESP_BASAL_SEQUENCE_END = RESP_BASAL_SEQUENCE_START + 2
+ private const val RESP_BASAL_PATCH_ID_START = 19
+ private const val RESP_BASAL_PATCH_ID_END = RESP_BASAL_PATCH_ID_START + 2
+ private const val RESP_BASAL_START_TIME_START = 21
+ private const val RESP_BASAL_START_TIME_END = RESP_BASAL_START_TIME_START + 4
+ }
init {
opCode = ACTIVATE.code
+ expectedMinRespLength = RESP_BASAL_START_TIME_END
}
override fun getRequest(): ByteArray {
- // TODO get activation commands
- return byteArrayOf(opCode)
+ /**
+ * byte 0: opCode
+ * byte 1: autoSuspendEnable // Value for auto mode, not used for AAPS
+ * byte 2: autoSuspendTime // Value for auto mode, not used for AAPS
+ * byte 3: expirationTimer // Expiration timer, 0 = no expiration 1 = 12 hour reminder and expiration after 3 days
+ * byte 4: alarmSetting // See AlarmSetting
+ * byte 5: lowSuspend // Value for auto mode, not used for AAPS
+ * byte 6: predictiveLowSuspend // Value for auto mode, not used for AAPS
+ * byte 7: predictiveLowSuspendRange // Value for auto mode, not used for AAPS
+ * byte 8-9: hourlyMaxInsulin // Max hourly dose of insulin not used for now, divided by 0.05
+ * byte 10-11: daylyMaxSet // Max daily dose of insulin not used for now, divided by 0.05
+ * byte 12-13: tddToday // Current TDD (of present day) not used for now, divided by 0.05
+ * byte 14: 1 // Always 1
+ * bytes 15 - end // Basal profile > see MedtrumPump
+ */
+
+ val patchExpiration: Byte = medtrumPump.desiredPatchExpiration.toByte()
+ val alarmSetting: Byte = medtrumPump.desiredAlarmSetting
+ val hourlyMaxInsulin: Int = round(medtrumPump.desiredHourlyMaxInsulin / 0.05).toInt()
+ val dailyMaxInsulin: Int = round(medtrumPump.desiredDailyMaxInsulin / 0.05).toInt()
+ val currentTDD: Double = tddCalculator.calculateToday()?.totalAmount?.div(0.05) ?: 0.0
+
+ return byteArrayOf(opCode) + 0.toByteArray(2) + patchExpiration + alarmSetting + 0.toByteArray(3) + hourlyMaxInsulin.toByteArray(2) + dailyMaxInsulin.toByteArray(2) + currentTDD.toInt()
+ .toByteArray(2) + 1.toByte() + basalProfile
}
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- // TODO
+ val medtrumTimeUtil = MedtrumTimeUtil()
+
+ val patchId = data.copyOfRange(RESP_PATCH_ID_START, RESP_PATCH_ID_END).toLong()
+ val time = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
+ val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
+ val basalValue = data.copyOfRange(RESP_BASAL_VALUE_START, RESP_BASAL_VALUE_END).toInt() * 0.05
+ val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
+ val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
+ val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+
+ medtrumPump.patchId = patchId
+ medtrumPump.lastTimeReceivedFromPump = time
+ medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
}
return success
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
index 240567ee58..f8c6a28729 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.AUTH_REQ
+import info.nightscout.pump.medtrum.comm.enums.CommandType.AUTH_REQ
import info.nightscout.pump.medtrum.encryption.Crypt
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacket.kt
index cd155332e6..3a2e2cbcca 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.CANCEL_BOLUS
+import info.nightscout.pump.medtrum.comm.enums.CommandType.CANCEL_BOLUS
class CancelBolusPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@@ -10,7 +10,11 @@ class CancelBolusPacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
}
override fun getRequest(): ByteArray {
- // TODO: Get bolus type
- return byteArrayOf(opCode)
+ // Bolus types:
+ // 1 = normal
+ // 2 = Extended
+ // 3 = Combi
+ val bolusType: Byte = 1 // Only support for normal bolus for now
+ return byteArrayOf(opCode) + bolusType
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
index 480806b31f..0f5aa165db 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
@@ -1,18 +1,46 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.CANCEL_TEMP_BASAL
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.CommandType.CANCEL_TEMP_BASAL
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.extension.toLong
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import javax.inject.Inject
class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+ @Inject lateinit var medtrumPump: MedtrumPump
+
+ companion object {
+
+ private const val RESP_BASAL_TYPE_START = 6
+ private const val RESP_BASAL_TYPE_END = RESP_BASAL_TYPE_START + 1
+ private const val RESP_BASAL_RATE_START = RESP_BASAL_TYPE_END
+ private const val RESP_BASAL_RATE_END = RESP_BASAL_RATE_START + 2
+ private const val RESP_BASAL_SEQUENCE_START = RESP_BASAL_RATE_END
+ private const val RESP_BASAL_SEQUENCE_END = RESP_BASAL_SEQUENCE_START + 2
+ private const val RESP_BASAL_PATCH_ID_START = RESP_BASAL_SEQUENCE_END
+ private const val RESP_BASAL_PATCH_ID_END = RESP_BASAL_PATCH_ID_START + 2
+ private const val RESP_BASAL_START_TIME_START = RESP_BASAL_PATCH_ID_END
+ private const val RESP_BASAL_START_TIME_END = RESP_BASAL_START_TIME_START + 4
+ }
+
init {
opCode = CANCEL_TEMP_BASAL.code
+ expectedMinRespLength = RESP_BASAL_START_TIME_END
}
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- // TODO Save basal
+ val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
+ val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05
+ val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
+ val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
+ val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+
+ medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
}
return success
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacket.kt
index a175a16537..22de4d50c3 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetDeviceTypePacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.GET_DEVICE_TYPE
+import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_DEVICE_TYPE
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
index 1ae6f4a759..ff1c5a7d53 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.GET_TIME
+import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_TIME
import info.nightscout.pump.medtrum.extension.toLong
class GetTimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacket.kt
index 561d28d5aa..e7adaeea2f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PollPatchPacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.POLL_PATCH
+import info.nightscout.pump.medtrum.comm.enums.CommandType.POLL_PATCH
class PollPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PrimePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PrimePacket.kt
index ceafc7ea67..70e0c12500 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PrimePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/PrimePacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.PRIME
+import info.nightscout.pump.medtrum.comm.enums.CommandType.PRIME
class PrimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
index dfd10abfef..33cb403bb7 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
@@ -1,8 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.READ_BOLUS_STATE
-import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.comm.enums.CommandType.READ_BOLUS_STATE
class ReadBolusStatePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@@ -10,7 +9,7 @@ class ReadBolusStatePacket(injector: HasAndroidInjector) : MedtrumPacket(injecto
companion object {
- private const val RESP_BOLUS_DATA_START = 6 // TODO: check this
+ private const val RESP_BOLUS_DATA_START = 6
}
init {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
index 133d1fec54..186aa0f463 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
@@ -1,16 +1,20 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_BASAL_PROFILE
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BASAL_PROFILE
+import javax.inject.Inject
-class SetBasalProfilePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+class SetBasalProfilePacket(injector: HasAndroidInjector, private val basalProfile: ByteArray) : MedtrumPacket(injector) {
+
+ @Inject lateinit var medtrumPump: MedtrumPump
init {
opCode = SET_BASAL_PROFILE.code
}
override fun getRequest(): ByteArray {
- // TODO get basal profile settings
- return byteArrayOf(opCode)
+ val basalType: Byte = 1 // Fixed to normal basal
+ return byteArrayOf(opCode) + basalType + basalProfile
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
index d048075bf2..3d3b8919cd 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
@@ -1,9 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_BOLUS_MOTOR
-import info.nightscout.pump.medtrum.extension.toByteArray
-import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BOLUS_MOTOR
class SetBolusMotorPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacket.kt
index 776ac4ba2c..4bfc2f1f33 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacket.kt
@@ -1,16 +1,23 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_BOLUS
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BOLUS
+import info.nightscout.pump.medtrum.extension.toByteArray
+import kotlin.math.round
-class SetBolusPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+class SetBolusPacket(injector: HasAndroidInjector, private val insulin: Double) : MedtrumPacket(injector) {
init {
opCode = SET_BOLUS.code
}
override fun getRequest(): ByteArray {
- // TODO get bolus settings
- return byteArrayOf(opCode) + 0.toByte()
+ // Bolus types:
+ // 1 = normal
+ // 2 = Extended
+ // 3 = Combi
+ val bolusType: Byte = 1 // Only support for normal bolus for now
+ val bolusAmount: Int = round(insulin / 0.05).toInt()
+ return byteArrayOf(opCode) + bolusType + bolusAmount.toByteArray(2) + 0.toByte()
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
index b434d790f4..fad3171614 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
@@ -1,17 +1,40 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_PATCH
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_PATCH
+import info.nightscout.pump.medtrum.extension.toByte
import info.nightscout.pump.medtrum.extension.toByteArray
+import javax.inject.Inject
+import kotlin.math.round
class SetPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+ @Inject lateinit var medtrumPump: MedtrumPump
+
init {
opCode = SET_PATCH.code
}
override fun getRequest(): ByteArray {
- // TODO get patch settings
- return byteArrayOf(opCode)
+ /**
+ * byte 0: opCode
+ * byte 1: alarmSetting // See AlarmSetting
+ * byte 2-3: hourlyMaxInsulin // Max hourly dose of insulin not used for now, divided by 0.05
+ * byte 4-5: dailyMaxSet // Max daily dose of insulin not used for now, divided by 0.05
+ * byte 6: expirationTimer // Expiration timer, 0 = no expiration 1 = 12 hour reminder and expiration
+ * byte 7: autoSuspendEnable // Value for auto mode, not used for AAPS
+ * byte 8: autoSuspendTime // Value for auto mode, not used for AAPS
+ * byte 9: lowSuspend // Value for auto mode, not used for AAPS
+ * byte 10: predictiveLowSuspend // Value for auto mode, not used for AAPS
+ * byte 11: predictiveLowSuspendRange // Value for auto mode, not used for AAPS
+ */
+
+ val alarmSetting: Byte = medtrumPump.desiredAlarmSetting
+ val hourlyMaxInsulin: Int = round(medtrumPump.desiredHourlyMaxInsulin / 0.05).toInt()
+ val dailyMaxInsulin: Int = round(medtrumPump.desiredDailyMaxInsulin / 0.05).toInt()
+ val patchExpiration: Byte = medtrumPump.desiredPatchExpiration.toByte()
+
+ return byteArrayOf(opCode) + alarmSetting + hourlyMaxInsulin.toByteArray(2) + dailyMaxInsulin.toByteArray(2) + patchExpiration + 0.toByteArray(5)
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
index 366e9c76de..3d11c0ecba 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
@@ -1,24 +1,61 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_TEMP_BASAL
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_TEMP_BASAL
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.extension.toLong
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import javax.inject.Inject
+import kotlin.math.round
-class SetTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+class SetTempBasalPacket(injector: HasAndroidInjector, private val absoluteRate: Double, private val durationInMinutes: Int) : MedtrumPacket(injector) {
+
+ @Inject lateinit var medtrumPump: MedtrumPump
+
+ companion object {
+
+ private const val RESP_BASAL_TYPE_START = 6
+ private const val RESP_BASAL_TYPE_END = RESP_BASAL_TYPE_START + 1
+ private const val RESP_BASAL_RATE_START = RESP_BASAL_TYPE_END
+ private const val RESP_BASAL_RATE_END = RESP_BASAL_RATE_START + 2
+ private const val RESP_BASAL_SEQUENCE_START = RESP_BASAL_RATE_END
+ private const val RESP_BASAL_SEQUENCE_END = RESP_BASAL_SEQUENCE_START + 2
+ private const val RESP_BASAL_PATCH_ID_START = RESP_BASAL_SEQUENCE_END
+ private const val RESP_BASAL_PATCH_ID_END = RESP_BASAL_PATCH_ID_START + 2
+ private const val RESP_BASAL_START_TIME_START = RESP_BASAL_PATCH_ID_END
+ private const val RESP_BASAL_START_TIME_END = RESP_BASAL_START_TIME_START + 4
+ }
init {
opCode = SET_TEMP_BASAL.code
- // TODO set expectedMinRespLength
+ expectedMinRespLength = RESP_BASAL_START_TIME_END
}
override fun getRequest(): ByteArray {
- // TODO get temp basal settings
- return byteArrayOf(opCode)
+ /**
+ * byte 0: opCode
+ * byte 1: tempBasalType
+ * byte 2-3: tempBasalRate
+ * byte 4-5: tempBasalDuration
+ */
+ val tempBasalType: Byte = 6 // Fixed to temp basal value for now
+ val tempBasalRate: Int = round(absoluteRate / 0.05).toInt()
+ val tempBasalDuration: Int = durationInMinutes
+ return byteArrayOf(opCode) + tempBasalType + tempBasalRate.toByteArray(2) + tempBasalDuration.toByteArray(2)
}
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- // TODO Save basal
+ val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
+ val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05
+ val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
+ val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
+ val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+
+ medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
}
return success
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacket.kt
index a2defdeb9a..a7a2c7d7a8 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_TIME
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_TIME
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacket.kt
index 2a1828167a..7993a7f169 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SET_TIME_ZONE
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_TIME_ZONE
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.shared.utils.DateUtil
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
index c037c10839..9eb38417b0 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
@@ -1,18 +1,35 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.STOP_PATCH
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.comm.enums.CommandType.STOP_PATCH
+import javax.inject.Inject
class StopPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+ @Inject lateinit var medtrumPump: MedtrumPump
+
+ companion object {
+
+ private const val RESP_STOP_SEQUENCE_START = 6
+ private const val RESP_STOP_SEQUENCE_END = RESP_STOP_SEQUENCE_START + 2
+ private const val RESP_STOP_PATCH_ID_START = RESP_STOP_SEQUENCE_END
+ private const val RESP_STOP_PATCH_ID_END = RESP_STOP_PATCH_ID_START + 2
+ }
+
init {
opCode = STOP_PATCH.code
+ expectedMinRespLength = RESP_STOP_PATCH_ID_END
}
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- // TODO
+ val stopSequence = data.copyOfRange(RESP_STOP_SEQUENCE_START, RESP_STOP_SEQUENCE_END).toInt()
+ val stopPatchId = data.copyOfRange(RESP_STOP_PATCH_ID_START, RESP_STOP_PATCH_ID_END).toInt()
+
+ medtrumPump.handleStopStatusUpdate(stopSequence, stopPatchId)
}
return success
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacket.kt
index 37a2b6e1be..c1615a2013 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SubscribePacket.kt
@@ -1,9 +1,8 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SUBSCRIBE
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SUBSCRIBE
import info.nightscout.pump.medtrum.extension.toByteArray
-import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
class SubscribePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
index a600013c74..3524eda324 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
@@ -1,7 +1,7 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
-import info.nightscout.pump.medtrum.comm.packets.CommandType.SYNCHRONIZE
+import info.nightscout.pump.medtrum.comm.enums.CommandType.SYNCHRONIZE
import info.nightscout.pump.medtrum.extension.toInt
class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/BoolExtension.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/BoolExtension.kt
new file mode 100644
index 0000000000..35728d68fd
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/extension/BoolExtension.kt
@@ -0,0 +1,8 @@
+package info.nightscout.pump.medtrum.extension
+
+fun Boolean.toByte(): Byte {
+ return if (this == true)
+ 0x1
+ else
+ 0x0
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
index 256bb850a0..e470f90b63 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
@@ -6,15 +6,15 @@ import java.time.Instant
class MedtrumTimeUtil {
fun getCurrentTimePumpSeconds() : Long {
- val startInstant = Instant.parse("2020-01-01T00:00:00Z")
+ val startInstant = Instant.parse("2014-01-01T00:00:00Z")
val currentInstant = Instant.now()
return Duration.between(startInstant, currentInstant).seconds
}
fun convertPumpTimeToSystemTimeSeconds(pumpTime: Long) : Long {
- val startInstant = Instant.parse("2020-01-01T00:00:00Z")
+ val startInstant = Instant.parse("2014-01-01T00:00:00Z")
val pumpInstant = startInstant.plusSeconds(pumpTime)
val epochInstant = Instant.EPOCH
return Duration.between(epochInstant, pumpInstant).seconds
}
-}
\ No newline at end of file
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt
index 529aebf36d..ef46cbe7e0 100644
--- a/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt
@@ -1,14 +1,16 @@
package info.nightscout.androidaps
+import android.content.Context
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.extensions.pureProfileFromJson
import info.nightscout.core.profile.ProfileSealed
import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.database.entities.EffectiveProfileSwitch
+import info.nightscout.database.entities.embedments.InsulinConfiguration
import info.nightscout.interfaces.Config
+import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin
-import info.nightscout.interfaces.profile.DefaultValueHelper
-import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.profile.ProfileStore
import info.nightscout.rx.bus.RxBus
@@ -16,28 +18,34 @@ import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.DateUtil
import org.json.JSONObject
import org.junit.jupiter.api.BeforeEach
+import org.mockito.ArgumentMatchers.anyDouble
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.invocation.InvocationOnMock
@Suppress("SpellCheckingInspection")
open class TestBaseWithProfile : TestBase() {
@Mock lateinit var activePluginProvider: ActivePlugin
@Mock lateinit var rh: ResourceHelper
+ @Mock lateinit var iobCobCalculator: IobCobCalculator
@Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var profileFunction: ProfileFunction
- @Mock lateinit var defaultValueHelper: DefaultValueHelper
- @Mock lateinit var dateUtil: DateUtil
@Mock lateinit var config: Config
+ @Mock lateinit var context: Context
+ lateinit var dateUtil: DateUtil
val rxBus = RxBus(aapsSchedulers, aapsLogger)
- val profileInjector = HasAndroidInjector {
- AndroidInjector {
- }
- }
+ val profileInjector = HasAndroidInjector { AndroidInjector { } }
private lateinit var validProfileJSON: String
- lateinit var validProfile: Profile
+ lateinit var validProfile: ProfileSealed.Pure
+ lateinit var effectiveProfileSwitch: EffectiveProfileSwitch
+
@Suppress("PropertyName") val TESTPROFILENAME = "someProfile"
@BeforeEach
@@ -45,7 +53,117 @@ open class TestBaseWithProfile : TestBase() {
validProfileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
"{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
"\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
+ dateUtil = Mockito.spy(DateUtil(context))
+ `when`(dateUtil.now()).thenReturn(1656358822000)
validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!)
+ effectiveProfileSwitch = EffectiveProfileSwitch(
+ timestamp = dateUtil.now(),
+ basalBlocks = validProfile.basalBlocks,
+ isfBlocks = validProfile.isfBlocks,
+ icBlocks = validProfile.icBlocks,
+ targetBlocks = validProfile.targetBlocks,
+ glucoseUnit = EffectiveProfileSwitch.GlucoseUnit.MMOL,
+ originalProfileName = "",
+ originalCustomizedName = "",
+ originalTimeshift = 0,
+ originalPercentage = 100,
+ originalDuration = 0,
+ originalEnd = 0,
+ insulinConfiguration = InsulinConfiguration("", 0, 0)
+ )
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ String.format(rh.gs(string), arg1)
+ }.`when`(rh).gs(anyInt(), anyInt())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ String.format(rh.gs(string), arg1)
+ }.`when`(rh).gs(anyInt(), anyDouble())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ String.format(rh.gs(string), arg1)
+ }.`when`(rh).gs(anyInt(), anyString())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ String.format(rh.gs(string), arg1, arg2)
+ }.`when`(rh).gs(anyInt(), anyString(), anyString())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ String.format(rh.gs(string), arg1, arg2)
+ }.`when`(rh).gs(anyInt(), anyString(), anyInt())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ String.format(rh.gs(string), arg1, arg2)
+ }.`when`(rh).gs(anyInt(), anyDouble(), anyString())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ String.format(rh.gs(string), arg1, arg2)
+ }.`when`(rh).gs(anyInt(), anyDouble(), anyInt())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ String.format(rh.gs(string), arg1, arg2)
+ }.`when`(rh).gs(anyInt(), anyInt(), anyInt())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ String.format(rh.gs(string), arg1, arg2)
+ }.`when`(rh).gs(anyInt(), anyInt(), anyString())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ val arg3 = invocation.getArgument(3)
+ String.format(rh.gs(string), arg1, arg2, arg3)
+ }.`when`(rh).gs(anyInt(), anyInt(), anyInt(), anyString())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ val arg3 = invocation.getArgument(3)
+ String.format(rh.gs(string), arg1, arg2, arg3)
+ }.`when`(rh).gs(anyInt(), anyInt(), anyString(), anyString())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ val arg3 = invocation.getArgument(3)
+ String.format(rh.gs(string), arg1, arg2, arg3)
+ }.`when`(rh).gs(anyInt(), anyDouble(), anyInt(), anyString())
+
+ Mockito.doAnswer { invocation: InvocationOnMock ->
+ val string = invocation.getArgument(0)
+ val arg1 = invocation.getArgument(1)
+ val arg2 = invocation.getArgument(2)
+ val arg3 = invocation.getArgument(3)
+ String.format(rh.gs(string), arg1, arg2, arg3)
+ }.`when`(rh).gs(anyInt(), anyString(), anyInt(), anyString())
+
}
fun getValidProfileStore(): ProfileStore {
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
new file mode 100644
index 0000000000..0c3a361a2b
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
@@ -0,0 +1,52 @@
+package info.nightscout.pump.medtrum
+
+import info.nightscout.core.extensions.pureProfileFromJson
+import info.nightscout.core.profile.ProfileSealed
+import org.json.JSONObject
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class MedtrumPumpTest : MedtrumTestBase() {
+
+ @Test fun buildMedtrumProfileArrayGivenProfileWhenValuesSetThenReturnCorrectByteArray() {
+ // Inputs
+ // Basal profile with 7 elements:
+ // 00:00 : 2.1
+ // 04:00 : 1.9
+ // 06:00 : 1.7
+ // 08:00 : 1.5
+ // 16:00 : 1.6
+ // 21:00 : 1.7
+ // 23:00 : 2
+ val profileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\"," +
+ "\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"},{\"time\":\"02:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\"," +
+ "\"basal\":[{\"time\":\"00:00\",\"value\":\"2.1\"},{\"time\":\"04:00\",\"value\":\"1.9\"},{\"time\":\"06:00\",\"value\":\"1.7\"}," +
+ "{\"time\":\"08:00\",\"value\":\"1.5\"},{\"time\":\"16:00\",\"value\":\"1.6\"},{\"time\":\"21:00\",\"value\":\"1.7\"},{\"time\":\"23:00\",\"value\":\"2\"}]," +
+ "\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
+ val profile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(profileJSON), dateUtil)!!)
+
+ // Call
+ val result = medtrumPump.buildMedtrumProfileArray(profile)
+
+ // Expected values
+ val expectedByteArray = byteArrayOf(7, 0, -96, 2, -16, 96, 2, 104, 33, 2, -32, -31, 1, -64, 3, 2, -20, 36, 2, 100, -123, 2)
+ assertEquals(expectedByteArray.contentToString(), result?.contentToString())
+ }
+
+ @Test fun buildMedtrumProfileArrayGiveProfileWhenValuesTooHighThenReturnNull() {
+ // Inputs
+ // Basal profile with 1 element:
+ // 00:00 : 600
+ val profileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\"," +
+ "\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"},{\"time\":\"02:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\"," +
+ "\"basal\":[{\"time\":\"00:00\",\"value\":\"600\"}]," +
+ "\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
+ val profile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(profileJSON), dateUtil)!!)
+
+ // Call
+ val result = medtrumPump.buildMedtrumProfileArray(profile)
+
+ // Expected values
+ assertNull(result)
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
index e1d6419c59..a1ef7c20c8 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
@@ -1,7 +1,22 @@
package info.nightscout.pump.medtrum
import info.nightscout.androidaps.TestBaseWithProfile
+import info.nightscout.shared.sharedPreferences.SP
+import info.nightscout.interfaces.profile.Instantiator
+import info.nightscout.interfaces.stats.TddCalculator
+import org.junit.jupiter.api.BeforeEach
+import org.mockito.Mock
open class MedtrumTestBase: TestBaseWithProfile() {
-
-}
\ No newline at end of file
+
+ @Mock lateinit var sp: SP
+ @Mock lateinit var instantiator: Instantiator
+ @Mock lateinit var tddCalculator: TddCalculator
+
+ lateinit var medtrumPump: MedtrumPump
+
+ @BeforeEach
+ fun setup() {
+ medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil, instantiator)
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
index 282f2c24da..d42b412c78 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
@@ -3,6 +3,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -12,22 +13,74 @@ class ActivatePacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is ActivatePacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
+ it.tddCalculator = tddCalculator
}
}
}
- @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ @Test fun getRequestGivenPacketWhenValuesSetThenReturnCorrectByteArray() {
// Inputs
- val opCode = 18
+ medtrumPump.desiredPatchExpiration = true
+ medtrumPump.desiredAlarmSetting = AlarmSetting.BEEP_ONLY.code
+ medtrumPump.desiredDailyMaxInsulin = 40
+ medtrumPump.desiredDailyMaxInsulin = 180
+
+ val basalProfile = byteArrayOf(3, 16, 14, 0, 0, 1, 2, 12, 12, 12)
// Call
- val packet = ActivatePacket(packetInjector)
+ val packet = ActivatePacket(packetInjector, basalProfile)
val result = packet.getRequest()
// Expected values
- assertEquals(1, result.size)
- assertEquals(opCode.toByte(), result[0])
+ val expectedByteArray = byteArrayOf(18, 0, 0, 1, 6, 0, 0, 0, 32, 3, 16, 14, 0, 0, 1, 3, 16, 14, 0, 0, 1, 2, 12, 12, 12)
+ assertEquals(expectedByteArray.contentToString(), result.contentToString())
+ }
+
+ @Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
+ // Inputs
+ medtrumPump.desiredPatchExpiration = true
+ medtrumPump.desiredAlarmSetting = AlarmSetting.BEEP_ONLY.code
+ medtrumPump.desiredDailyMaxInsulin = 40
+ medtrumPump.desiredDailyMaxInsulin = 180
+
+ val basalProfile = byteArrayOf(3, 16, 14, 0, 0, 1, 2, 12, 12, 12)
+ val response = byteArrayOf(26, 18, 19, 1, 0, 0, 41, 0, 0, 0, -104, 91, 28, 17, 1, 30, 0, 1, 0, 41, 0, -104, 91, 28, 17)
+
+ // Call
+ val packet = ActivatePacket(packetInjector, basalProfile)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ val expectedPatchId = 41L
+ val expectedTime = 1675605528L
+ val exptectedBasalType = 1
+ val expectedBasalRate = 1.5
+ val expectedBasalSequence = 1
+ val expectedBasalPatchId = 41
+ val expectedBasalStart = 1675605528L
+
+ assertEquals(true, result)
+ assertEquals(expectedPatchId, medtrumPump.patchId)
+ assertEquals(expectedTime, medtrumPump.lastTimeReceivedFromPump)
+ assertEquals(exptectedBasalType, medtrumPump.lastBasalType)
+ assertEquals(expectedBasalRate, medtrumPump.lastBasalRate, 0.01)
+ assertEquals(expectedBasalSequence, medtrumPump.lastBasalSequence)
+ assertEquals(expectedBasalPatchId, medtrumPump.lastBasalPatchId)
+ assertEquals(expectedBasalStart, medtrumPump.lastBasalStartTime)
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val response = byteArrayOf(26, 18, 19, 1, 0, 0, 41, 0, 0, 0, -104, 91, 28, 17, 1, 30, 0, 1, 0, 41, 0, -104, 91, 28)
+
+ // Call
+ val packet = ActivatePacket(packetInjector, byteArrayOf())
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertFalse(result)
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
index 294670f0fe..01b9248288 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
@@ -52,8 +52,8 @@ class AuthorizePacketTest : MedtrumTestBase() {
// Expected values
val swString = "$swVerX.$swVerY.$swVerZ"
- assertEquals(true, result)
- assertEquals(false, packet.failed)
+ assertTrue(result)
+ assertFalse(packet.failed)
assertEquals(deviceType, packet.deviceType)
assertEquals(swString, packet.swVersion)
}
@@ -70,7 +70,7 @@ class AuthorizePacketTest : MedtrumTestBase() {
val result = packet.handleResponse(response)
// Expected values
- assertEquals(false, result)
- assertEquals(true, packet.failed)
+ assertFalse(result)
+ assertTrue(packet.failed)
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacketTest.kt
index 94a63e3022..fcca4a53fb 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelBolusPacketTest.kt
@@ -27,7 +27,8 @@ class CancelBolusPacketTest : MedtrumTestBase() {
val result = packet.getRequest()
// Expected values
- assertEquals(1, result.size)
- assertEquals(opCode.toByte(), result[0])
+ val expectedByteArray = byteArrayOf(opCode.toByte()) + 1.toByte()
+ assertEquals(2, result.size)
+ assertEquals(expectedByteArray.contentToString(), result.contentToString())
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
index 3bfc30ef4b..1f08aa0e45 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
@@ -12,8 +12,9 @@ class CancelTempBasalPacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is CancelTempBasalPacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
}
}
}
@@ -30,4 +31,40 @@ class CancelTempBasalPacketTest : MedtrumTestBase() {
assertEquals(1, result.size)
assertEquals(opCode.toByte(), result[0])
}
+
+ @Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
+ // Inputs
+ val repsonse = byteArrayOf(18, 25, 16, 0, 0, 0, 1, 22, 0, 3, 0, -110, 0, -32, -18, 88, 17)
+
+ // Call
+ val packet = CancelTempBasalPacket(packetInjector)
+ val result = packet.handleResponse(repsonse)
+
+ // Expected values
+ val expectedBasalType = 1
+ val expectedBasalRate = 1.1
+ val expectedBasalSequence = 3
+ val expectedStartTime = 1679575392L
+ val expectedPatchId = 146
+
+ assertTrue(result)
+ assertEquals(expectedBasalType, medtrumPump.lastBasalType)
+ assertEquals(expectedBasalRate, medtrumPump.lastBasalRate, 0.01)
+ assertEquals(expectedBasalSequence, medtrumPump.lastBasalSequence)
+ assertEquals(expectedStartTime, medtrumPump.lastBasalStartTime)
+ assertEquals(expectedPatchId, medtrumPump.lastBasalPatchId)
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val response = byteArrayOf(18, 25, 16, 0, 0, 0, 1, 22, 0, 3, 0, -110, 0, -32, -18, 88)
+
+ // Call
+ val packet = CancelTempBasalPacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertFalse(result)
+ assertTrue(packet.failed)
+ }
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacketTest.kt
index 05bb898792..c05b79a7be 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacketTest.kt
@@ -19,7 +19,7 @@ class ReadBolusStatePacketTest : MedtrumTestBase() {
}
}
- @Test fun handleResponseGivenResponseWhenMessageIsCorrectLengthThenResultTrue() {
+ @Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
// Inputs
val opCode = 34
val responseCode = 0
@@ -31,8 +31,8 @@ class ReadBolusStatePacketTest : MedtrumTestBase() {
val result = packet.handleResponse(response)
// Expected values
- assertEquals(true, result)
- assertEquals(false, packet.failed)
+ assertTrue(result)
+ assertFalse(packet.failed)
assertEquals(bolusData.contentToString(), packet.bolusData.contentToString())
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
index e257795771..18895facf9 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
@@ -12,8 +12,9 @@ class SetBasalProfilePacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is SetBasalProfilePacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
}
}
}
@@ -21,13 +22,14 @@ class SetBasalProfilePacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
// Inputs
val opCode = 21
+ val basalProfile = byteArrayOf(8, 2, 3, 4, -1, 0, 0, 0, 0)
// Call
- val packet = SetBasalProfilePacket(packetInjector)
+ val packet = SetBasalProfilePacket(packetInjector, basalProfile)
val result = packet.getRequest()
// Expected values
- assertEquals(1, result.size)
- assertEquals(opCode.toByte(), result[0])
+ val expected = byteArrayOf(opCode.toByte()) + 1.toByte() + basalProfile
+ assertEquals(expected.contentToString(), result.contentToString())
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacketTest.kt
index 6d4f5413c3..1f5339cf28 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBolusPacketTest.kt
@@ -20,15 +20,14 @@ class SetBolusPacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
// Inputs
- val opCode = 19
+ val insulin = 2.35
// Call
- val packet = SetBolusPacket(packetInjector)
+ val packet = SetBolusPacket(packetInjector, insulin)
val result = packet.getRequest()
// Expected values
- // TODO correct value's
- assertEquals(1, result.size)
- assertEquals(opCode.toByte(), result[0])
+ val expected = byteArrayOf(19, 1, 47, 0, 0)
+ assertEquals(expected.contentToString(), result.contentToString())
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
index 7e360909eb..eb15c6f032 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
@@ -3,32 +3,36 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
import org.junit.jupiter.api.Test
import org.junit.Assert.*
-class SetPatchPacket : MedtrumTestBase() {
+class SetPatchPacketTest : MedtrumTestBase() {
/** Test packet specific behavoir */
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is SetPatchPacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
}
}
}
- @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ @Test fun getRequestGivenValuesWhenCalledThenReturnValidArray() {
// Inputs
- val opCode = 35
+ medtrumPump.desiredPatchExpiration = false
+ medtrumPump.desiredAlarmSetting = AlarmSetting.LIGHT_AND_VIBRATE.code
+ medtrumPump.desiredDailyMaxInsulin = 40
+ medtrumPump.desiredDailyMaxInsulin = 180
// Call
- val packet = SetBolusPacket(packetInjector)
+ val packet = SetPatchPacket(packetInjector)
val result = packet.getRequest()
// Expected values
- // TODO correct value's
- assertEquals(1, result.size)
- assertEquals(opCode.toByte(), result[0])
+ val expected = byteArrayOf(35, 1, 32, 3, 16, 14, 0, 0, 0, 0, 0, 0)
+ assertEquals(expected.contentToString(), result.contentToString())
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
index 5643aa5c9b..ac125c3b69 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
@@ -3,7 +3,6 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
-import info.nightscout.pump.medtrum.extension.toByteArray
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -13,50 +12,65 @@ class SetTempBasalPacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is SetTempBasalPacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
}
}
}
@Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
// Inputs
- val opCode = 24
+ val absoluteRate = 1.25
+ val duration = 60
// Call
- val packet = SetTempBasalPacket(packetInjector)
+ val packet = SetTempBasalPacket(packetInjector, absoluteRate, duration)
val result = packet.getRequest()
// Expected values
- assertEquals(1, result.size)
- assertEquals(opCode.toByte(), result[0])
+ val expected = byteArrayOf(24, 6, 25, 0, 60, 0)
+ assertEquals(expected.contentToString(), result.contentToString())
}
- @Test fun getRequestGivenPacketWhenCalledThenReturnOpCodeAndDuration() {
- // TODO
- }
+ @Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
+ // Inputs
+ val absoluteRate = 1.25
+ val duration = 60
- @Test fun getRequestGivenPacketWhenCalledThenReturnOpCodeAndDurationAndRate() {
- // TODO
- }
+ val response = byteArrayOf(18, 24, 12, 0, 0, 0, 6, 25, 0, 2, 0, -110, 0, -56, -19, 88, 17, -89, 0)
- @Test fun handleResponseGivenResponseWhenMessageIsCorrectLengthThenResultTrue() {
- // TODO
+ // Call
+ val packet = SetTempBasalPacket(packetInjector, absoluteRate, duration)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ val expectedBasalType = 6
+ val expectedBasalRate = 1.25
+ val expectedBasalSequence = 2
+ val expectedStartTime = 1679575112L
+ val expectedPatchId = 146
+
+ assertTrue(result)
+ assertEquals(expectedBasalType, medtrumPump.lastBasalType)
+ assertEquals(expectedBasalRate, medtrumPump.lastBasalRate, 0.01)
+ assertEquals(expectedBasalSequence, medtrumPump.lastBasalSequence)
+ assertEquals(expectedStartTime, medtrumPump.lastBasalStartTime)
+ assertEquals(expectedPatchId, medtrumPump.lastBasalPatchId)
}
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
// Inputs
- val opCode = 24
- val responseCode = 0
- val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2)
+ val absoluteRate = 1.25
+ val duration = 60
- // Call
- val packet = ReadBolusStatePacket(packetInjector)
+ val response = byteArrayOf(18, 24, 12, 0, 0, 0, 6, 25, 0, 2, 0, -110, 0, -56, -19, 88)
+
+ // Call
+ val packet = SetTempBasalPacket(packetInjector, absoluteRate, duration)
val result = packet.handleResponse(response)
// Expected values
- assertEquals(false, result)
- assertEquals(true, packet.failed)
- // assertEquals(byteArrayOf().contentToString(), packet.bolusData.contentToString()) TODO
+ assertFalse(result)
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacketTest.kt
index 08fba5ae89..e4eed05395 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimePacketTest.kt
@@ -23,7 +23,7 @@ class SetTimePacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
// Inputs
val opCode = 10
- val time = MedtrumTimeUtil().getCurrentTimePumpSeconds() // TODO: Mock time proper?
+ val time = MedtrumTimeUtil().getCurrentTimePumpSeconds()
// Call
val packet = SetTimePacket(packetInjector)
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacketTest.kt
index cf2d858ee0..532b55853f 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTimeZonePacketTest.kt
@@ -26,8 +26,8 @@ class SetTimeZonePacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
// Inputs
val opCode = 12
- val time = MedtrumTimeUtil().getCurrentTimePumpSeconds() // TODO: Mock time proper?
- val offsetMins = dateUtil.getTimeZoneOffsetMinutes(dateUtil.now()) // TODO: Mock time proper?
+ val time = MedtrumTimeUtil().getCurrentTimePumpSeconds()
+ val offsetMins = dateUtil.getTimeZoneOffsetMinutes(dateUtil.now())
// Call
val packet = SetTimeZonePacket(packetInjector)
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
index 53ffcfe9d0..f626a2af3f 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
@@ -12,8 +12,9 @@ class StopPatchPacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is StopPatchPacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
}
}
}
@@ -31,5 +32,31 @@ class StopPatchPacketTest : MedtrumTestBase() {
assertEquals(opCode.toByte(), result[0])
}
- // TODO: Add tests for the response
+ @Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
+ // Inputs
+ val response = byteArrayOf(11, 31, 10, 0, 0, 0, 23, 0, -110, 0, -5, 0)
+
+ // Call
+ val packet = StopPatchPacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ val expectedPatchId = 146
+ val expectedStopSequence = 23
+ assertEquals(expectedPatchId, medtrumPump.lastStopPatchId)
+ assertEquals(expectedStopSequence, medtrumPump.lastStopSequence)
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val response = byteArrayOf(11, 31, 10, 0, 0, 0, 23, 0, -110)
+
+ // Call
+ val packet = StopPatchPacket(packetInjector)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertFalse(result)
+ assertTrue(packet.failed)
+ }
}
From cafdd6cf8fb6ca30f2c4795a45a383522f39f82a Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 25 Mar 2023 16:55:06 +0100
Subject: [PATCH 014/116] Implement GetRecordPacket (initial)
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 5 ++
.../pump/medtrum/comm/enums/CommandType.kt | 3 +-
.../medtrum/comm/packets/GetRecordPacket.kt | 53 +++++++++++++++++++
.../comm/packets/GetRecordPacketTest.kt | 46 ++++++++++++++++
4 files changed, 106 insertions(+), 1 deletion(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacketTest.kt
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 0435ff973c..d36f30c91a 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -55,6 +55,7 @@ class MedtrumPump @Inject constructor(
var patchId = 0L
var lastTimeReceivedFromPump = 0L // Time in seconds!
+ var lastKnownSequenceNumber = 0
// Pump history
@@ -97,13 +98,17 @@ class MedtrumPump @Inject constructor(
lastBasalType = basalType
lastBasalRate = basalRate
lastBasalSequence = basalSequence
+ lastKnownSequenceNumber = basalSequence
lastBasalPatchId = basalPatchId
lastBasalStartTime = basalStartTime
+ // TODO Handle history
}
fun handleStopStatusUpdate(stopSequence: Int, stopPatchId: Int) {
aapsLogger.debug(LTag.PUMP, "handleStopStatusUpdate: stopSequence: $stopSequence stopPatchId: $stopPatchId")
lastStopSequence = stopSequence
+ lastKnownSequenceNumber = stopSequence
lastStopPatchId = stopPatchId
+ // TODO Handle history
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
index 8b6119c0b4..b38941ac91 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
@@ -19,5 +19,6 @@ enum class CommandType(val code: Byte) {
STOP_PATCH(31),
READ_BOLUS_STATE(34),
SET_PATCH(35),
- SET_BOLUS_MOTOR(36)
+ SET_BOLUS_MOTOR(36),
+ GET_RECORD(99)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
new file mode 100644
index 0000000000..9aa9c2e2be
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -0,0 +1,53 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.extension.toLong
+import javax.inject.Inject
+
+class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int) : MedtrumPacket(injector) {
+
+ @Inject lateinit var medtrumPump: MedtrumPump
+
+ companion object {
+
+ private const val RESP_RECORD_HEADER_START = 6
+ private const val RESP_RECORD_HEADER_END = RESP_RECORD_HEADER_START + 1
+ private const val RESP_RECORD_UNKNOWN_START = RESP_RECORD_HEADER_END
+ private const val RESP_RECORD_UNKNOWN_END = RESP_RECORD_UNKNOWN_START + 1
+ private const val RESP_RECORD_TYPE_START = RESP_RECORD_UNKNOWN_END
+ private const val RESP_RECORD_TYPE_END = RESP_RECORD_TYPE_START + 1
+ private const val RESP_RECORD_SERIAL_START = RESP_RECORD_TYPE_END
+ private const val RESP_RECORD_SERIAL_END = RESP_RECORD_SERIAL_START + 4
+ private const val RESP_RECORD_PATCHID_START = RESP_RECORD_SERIAL_END
+ private const val RESP_RECORD_PATCHID_END = RESP_RECORD_PATCHID_START + 2
+ private const val RESP_RECORD_DATA_START = RESP_RECORD_PATCHID_END
+ }
+
+ init {
+ opCode = GET_RECORD.code
+ expectedMinRespLength = RESP_RECORD_DATA_START
+ }
+
+ override fun getRequest(): ByteArray {
+ return byteArrayOf(opCode) + recordIndex.toByteArray(2) + medtrumPump.patchId.toByteArray(2)
+ }
+
+ override fun handleResponse(data: ByteArray): Boolean {
+ val success = super.handleResponse(data)
+ if (success) {
+ val recordHeader = data.copyOfRange(RESP_RECORD_HEADER_START, RESP_RECORD_HEADER_END).toInt()
+ val recordUnknown = data.copyOfRange(RESP_RECORD_UNKNOWN_START, RESP_RECORD_UNKNOWN_END).toInt()
+ val recordType = data.copyOfRange(RESP_RECORD_TYPE_START, RESP_RECORD_TYPE_END).toInt()
+ val recordSerial = data.copyOfRange(RESP_RECORD_SERIAL_START, RESP_RECORD_SERIAL_END).toLong()
+ val recordPatchId = data.copyOfRange(RESP_RECORD_PATCHID_START, RESP_RECORD_PATCHID_END).toInt()
+
+ // TODO Handle history records
+ }
+
+ return success
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacketTest.kt
new file mode 100644
index 0000000000..2816996dad
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacketTest.kt
@@ -0,0 +1,46 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class GetRecordPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is GetRecordPacket) {
+ it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val recordIndex = 4
+ medtrumPump.patchId = 146
+
+ // Call
+ val packet = GetRecordPacket(packetInjector, recordIndex)
+ val result = packet.getRequest()
+
+ // Expected values
+ val expected = byteArrayOf(99, 4, 0, -110, 0)
+ assertEquals(expected.contentToString(), result.contentToString())
+ }
+
+ @Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
+ assertTrue(false)
+ // TODO: Implement history and test
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ assertTrue(false)
+ // TODO: Implement history and test
+ }
+}
\ No newline at end of file
From af6445a3dc699c9591786408bcdb71ff36190a01 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 28 Mar 2023 19:26:58 +0200
Subject: [PATCH 015/116] NotificationPacket
---
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 8 +-
.../nightscout/pump/medtrum/MedtrumPump.kt | 36 +--
.../medtrum/comm/enums/MedtrumPumpState.kt | 9 +-
.../medtrum/comm/packets/ActivatePacket.kt | 7 +-
.../medtrum/comm/packets/GetTimePacket.kt | 8 +-
.../comm/packets/NotificationPacket.kt | 206 ++++++++++++++++++
.../comm/packets/ReadBolusStatePacket.kt | 1 +
.../medtrum/comm/packets/SynchronizePacket.kt | 46 +++-
.../pump/medtrum/di/MedtrumCommModule.kt | 4 +
.../pump/medtrum/services/BLEComm.kt | 21 +-
.../pump/medtrum/services/MedtrumService.kt | 35 ++-
.../medtrum/comm/packets/GetTimePacketTest.kt | 8 +-
.../medtrum/comm/packets/MedtrumPacketTest.kt | 2 +-
.../comm/packets/NotificationPacketTest.kt | 39 ++++
.../comm/packets/SynchronizePacketTest.kt | 18 +-
15 files changed, 396 insertions(+), 52 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacketTest.kt
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index d0c319acb8..e264320ba5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -26,6 +26,7 @@ import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.queue.CustomCommand
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.TimeChangeType
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
import info.nightscout.pump.medtrum.services.MedtrumService
import info.nightscout.rx.AapsSchedulers
@@ -62,6 +63,7 @@ class MedtrumPlugin @Inject constructor(
private val fabricPrivacy: FabricPrivacy,
private val dateUtil: DateUtil,
private val pumpSync: PumpSync,
+ private val medtrumPump: MedtrumPump,
private val uiInteraction: UiInteraction,
private val profileFunction: ProfileFunction
) : PumpPluginBase(
@@ -116,15 +118,15 @@ class MedtrumPlugin @Inject constructor(
}
override fun isInitialized(): Boolean {
- return false
+ return medtrumPump.pumpState > MedtrumPumpState.EJECTED
}
override fun isSuspended(): Boolean {
- return true
+ return medtrumPump.pumpState < MedtrumPumpState.ACTIVE || medtrumPump.pumpState > MedtrumPumpState.ACTIVE_ALT
}
override fun isBusy(): Boolean {
- return true
+ return false
}
override fun isConnected(): Boolean {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index d36f30c91a..6bda29514f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -40,24 +40,21 @@ class MedtrumPump @Inject constructor(
var pumpState = MedtrumPumpState.NONE // TODO save in SP
var patchActivationState = PatchActivationState.NONE // TODO save in SP
- // TODO set these setting on init
- // User settings (desired values, to be set on pump)
- var desiredPatchExpiration = false
- var desiredAlarmSetting = AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code
- var desiredHourlyMaxInsulin: Int = 40
- var desiredDailyMaxInsulin: Int = 180
-
- // User settings (actual value's as reported by pump)
-
- // Alarm settings
-
- // Pump status
-
var patchId = 0L
- var lastTimeReceivedFromPump = 0L // Time in seconds!
var lastKnownSequenceNumber = 0
+ var lastTimeReceivedFromPump = 0L // Time in seconds!
+ var suspendTime = 0L // Time in seconds!
+ var patchStartTime = 0L // Time in seconds!
+ var patchAge = 0L // Time in seconds!
+
+ var reservoir = 0.0
+ var primeProgress = 0
- // Pump history
+ var batteryVoltage_A = 0.0
+ var batteryVoltage_B = 0.0
+
+ var alarmFlags = 0
+ var alarmParameter = 0
// Last basal status update
var lastBasalType = 0
@@ -70,6 +67,15 @@ class MedtrumPump @Inject constructor(
var lastStopSequence = 0
var lastStopPatchId = 0
+
+ // TODO set these setting on init
+ // User settings (desired values, to be set on pump)
+ var desiredPatchExpiration = false
+ var desiredAlarmSetting = AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code
+ var desiredHourlyMaxInsulin: Int = 40
+ var desiredDailyMaxInsulin: Int = 180
+
+
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
val list = nsProfile.getBasalValues()
var basals = byteArrayOf()
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
index eabfcac976..e861c8866a 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
@@ -3,7 +3,7 @@ package info.nightscout.pump.medtrum.comm.enums
enum class MedtrumPumpState(val state: Byte) {
NONE(0),
IDLE(1),
- DELIVERING(2),
+ FILL(2),
PRIMING(3),
PRIMED(4),
EJECTING(5),
@@ -25,5 +25,10 @@ enum class MedtrumPumpState(val state: Byte) {
BASE_FAULT(101),
BATTERY_OUT(102),
NO_CALIBRATION(103),
- STOPPED(128.toByte())
+ STOPPED(128.toByte());
+
+ companion object {
+ fun fromByte(state: Byte) = values().find { it.state == state }
+ ?: throw IllegalAccessException("")
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
index 3e53670032..5911d09525 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
@@ -50,9 +50,9 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
* byte 5: lowSuspend // Value for auto mode, not used for AAPS
* byte 6: predictiveLowSuspend // Value for auto mode, not used for AAPS
* byte 7: predictiveLowSuspendRange // Value for auto mode, not used for AAPS
- * byte 8-9: hourlyMaxInsulin // Max hourly dose of insulin not used for now, divided by 0.05
- * byte 10-11: daylyMaxSet // Max daily dose of insulin not used for now, divided by 0.05
- * byte 12-13: tddToday // Current TDD (of present day) not used for now, divided by 0.05
+ * byte 8-9: hourlyMaxInsulin // Max hourly dose of insulin, divided by 0.05
+ * byte 10-11: daylyMaxSet // Max daily dose of insulin, divided by 0.05
+ * byte 12-13: tddToday // Current TDD (of present day), divided by 0.05
* byte 14: 1 // Always 1
* bytes 15 - end // Basal profile > see MedtrumPump
*/
@@ -82,6 +82,7 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
medtrumPump.patchId = patchId
medtrumPump.lastTimeReceivedFromPump = time
+ // TODO: Handle basal here, and report to AAPS directly
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
index ff1c5a7d53..cedaf6fdbe 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
@@ -1,12 +1,15 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_TIME
import info.nightscout.pump.medtrum.extension.toLong
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import javax.inject.Inject
class GetTimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
- var time: Long = 0
+ @Inject lateinit var medtrumPump: MedtrumPump
companion object {
@@ -22,7 +25,8 @@ class GetTimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- time = data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong()
+ val time = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
+ medtrumPump.lastTimeReceivedFromPump = time
}
return success
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
new file mode 100644
index 0000000000..6cb5a5bfa6
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -0,0 +1,206 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
+import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.extension.toLong
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+import kotlin.experimental.and
+
+class NotificationPacket(val injector: HasAndroidInjector) {
+
+ /**
+ * This is a bit of a special packet, as it is not a command packet
+ * but a notification packet. It is sent by the pump to the phone
+ * when the pump has a notification to send.
+ *
+ * Notifications are sent regualary, regardless of the pump state.
+ *
+ * There can be multiple messages in one packet, this is noted by the fieldMask.
+ *
+ * Byte 1: State (Handle a state change directly? before analyzing further?)
+ * Byte 2-3: FieldMask (BitMask which tells the fields present in the message)
+ * Byte 4-end : status data
+ *
+ * When multiple fields are in the message, the data is concatenated.
+ * This kind of message can also come as a response of SynchronizePacket,
+ * and can be handled here by handleMaskedMessage() as well.
+ */
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var medtrumPump: MedtrumPump
+
+ companion object {
+ private const val NOTIF_STATE_START = 0
+ private const val NOTIF_STATE_END = NOTIF_STATE_START + 1
+
+ private const val MASK_SUSPEND = 0x01
+ private const val MASK_NORMAL_BOLUS = 0x02
+ private const val MASK_EXTENDED_BOLUS = 0x04
+ private const val MASK_BASAL = 0x08
+
+ private const val MASK_SETUP = 0x10
+ private const val MASK_RESERVOIR = 0x20
+ private const val MASK_LIFE_TIME = 0x40
+ private const val MASK_BATTERY = 0x80
+
+ private const val MASK_STORAGE = 0x100
+ private const val MASK_ALARM = 0x200
+ private const val MASK_START_TIME = 0x400
+ private const val MASK_UNKNOWN_1 = 0x800
+
+ private const val MASK_UNUSED_CGM = 0x1000
+ private const val MASK_UNUSED_COMMAND_CONFIRM = 0x2000
+ private const val MASK_UNUSED_AUTO_STATUS = 0x4000
+ private const val MASK_UNUSED_LEGACY = 0x8000
+ }
+
+ init {
+ injector.androidInjector().inject(this)
+ }
+
+ fun handleNotification(notification: ByteArray) {
+ val state = MedtrumPumpState.fromByte(notification[0])
+ aapsLogger.debug(LTag.PUMPCOMM, "Notification state: $state, current state: ${medtrumPump.pumpState}")
+
+ // TODO: Do we need to emit an event on state change?
+ medtrumPump.pumpState = state
+
+ if (notification.size > NOTIF_STATE_END) {
+ handleMaskedMessage(notification.copyOfRange(NOTIF_STATE_END, notification.size))
+ }
+ }
+
+ /**
+ * Handle a message with a field mask, can be used by other packets as well
+ */
+ fun handleMaskedMessage(data: ByteArray) {
+ val fieldMask = data.copyOfRange(0, 2).toInt()
+ var offset = 2
+
+ aapsLogger.debug(LTag.PUMPCOMM, "Message field mask: $fieldMask")
+
+ if (fieldMask and MASK_SUSPEND != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Suspend notification received")
+ medtrumPump.suspendTime = data.copyOfRange(offset, offset + 4).toLong()
+ aapsLogger.debug(LTag.PUMPCOMM, "Suspend time: ${medtrumPump.suspendTime}")
+ offset += 4
+ }
+
+ if (fieldMask and MASK_NORMAL_BOLUS != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
+ var bolusData = data.copyOfRange(offset, offset + 1).toInt()
+ var bolusType = bolusData and 0x7F
+ var bolusCompleted = (bolusData shr 7) and 0x01
+ var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() / 0.05
+ // TODO Sync bolus flow:
+ // If bolus is known add status
+ // If bolus is not known start read bolus
+ // When bolus is completed, remove bolus from medtrumPump
+ aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
+ offset += 3
+ }
+
+ if (fieldMask and MASK_EXTENDED_BOLUS != 0) {
+ aapsLogger.error(LTag.PUMPCOMM, "Extended bolus notification received, extended bolus not supported!")
+ // TODO Handle error and stop pump if this happens
+ offset += 3
+ }
+
+ if (fieldMask and MASK_BASAL != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Basal notification received")
+ var basalType = data.copyOfRange(offset, offset + 1)
+ var basalSequence = data.copyOfRange(offset + 1, offset + 3)
+ var basalInterval = data.copyOfRange(offset + 3, offset + 7)
+ var basalRateAndDelivery = data.copyOfRange(offset + 7, offset + 10).toInt()
+ var basalRate = basalRateAndDelivery and 0xFFF
+ var basalDelivery = (basalRateAndDelivery shr 12)
+ aapsLogger.debug(LTag.PUMPCOMM, "Basal type: $basalType, basal sequence: $basalSequence, basal interval: $basalInterval, basal rate: $basalRate, basal delivery: $basalDelivery")
+ // TODO Sync basal flow
+ offset += 10
+ }
+
+ if (fieldMask and MASK_SETUP != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Setup notification received")
+ medtrumPump.primeProgress = data.copyOfRange(offset, offset + 1).toInt()
+ aapsLogger.debug(LTag.PUMPCOMM, "Prime progress: ${medtrumPump.primeProgress}")
+ offset += 1
+ }
+
+ if (fieldMask and MASK_RESERVOIR != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Reservoir notification received")
+ medtrumPump.reservoir = data.copyOfRange(offset, offset + 2).toInt() * 0.05
+ aapsLogger.debug(LTag.PUMPCOMM, "Reservoir: ${medtrumPump.reservoir}")
+ offset += 2
+ }
+
+ if (fieldMask and MASK_LIFE_TIME != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Life time notification received")
+ // TODO Check if timezone offset needs to be added
+ medtrumPump.patchAge = data.copyOfRange(offset, offset + 4).toLong()
+ aapsLogger.debug(LTag.PUMPCOMM, "Patch age: ${medtrumPump.patchAge}")
+ offset += 4
+ }
+
+ if (fieldMask and MASK_BATTERY != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Battery notification received")
+ var parameter = data.copyOfRange(offset, offset + 3).toInt()
+ // Precision for voltage A is a guess, voltage B is the important one, threshold: < 2.64
+ medtrumPump.batteryVoltage_A = (parameter and 0xFFF) / 512.0
+ medtrumPump.batteryVoltage_B = (parameter shr 12) / 512.0
+ aapsLogger.debug(LTag.PUMPCOMM, "Battery voltage A: ${medtrumPump.batteryVoltage_A}, battery voltage B: ${medtrumPump.batteryVoltage_B}")
+ offset += 3
+ }
+
+ if (fieldMask and MASK_STORAGE != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Storage notification received")
+ // TODO, trigger check for new sequence?
+ medtrumPump.lastKnownSequenceNumber = data.copyOfRange(offset, offset + 2).toInt()
+ medtrumPump.patchId = data.copyOfRange(offset + 2, offset + 4).toLong()
+ aapsLogger.debug(LTag.PUMPCOMM, "Last known sequence number: ${medtrumPump.lastKnownSequenceNumber}, patch id: ${medtrumPump.patchId}")
+ offset += 4
+ }
+
+ if (fieldMask and MASK_ALARM != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Alarm notification received")
+ // Set only flags here, Alarms will be picked up by the state change
+ medtrumPump.alarmFlags = data.copyOfRange(offset, offset + 2).toInt()
+ medtrumPump.alarmParameter = data.copyOfRange(offset + 2, offset + 4).toInt()
+ aapsLogger.debug(LTag.PUMPCOMM, "Alarm flags: ${medtrumPump.alarmFlags}, alarm parameter: ${medtrumPump.alarmParameter}")
+ offset += 4
+ }
+
+ if (fieldMask and MASK_START_TIME != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Start time notification received")
+ medtrumPump.patchStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(offset, offset + 4).toLong())
+ aapsLogger.debug(LTag.PUMPCOMM, "Patch start time: ${medtrumPump.patchStartTime}")
+ offset += 4
+ }
+
+ if (fieldMask and MASK_UNKNOWN_1 != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Unknown 1 notification received, not handled!")
+ }
+
+ if (fieldMask and MASK_UNUSED_CGM != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Unused CGM notification received, not handled!")
+ }
+
+ if (fieldMask and MASK_UNUSED_COMMAND_CONFIRM != 0) {
+ // This one is a warning, as this happens we need to know about it, and maybe implement
+ aapsLogger.warn(LTag.PUMPCOMM, "Unused command confirm notification received, not handled!")
+ }
+
+ if (fieldMask and MASK_UNUSED_AUTO_STATUS != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Unused auto status notification received, not handled!")
+ }
+
+ if (fieldMask and MASK_UNUSED_LEGACY != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Unused legacy notification received, not handled!")
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
index 33cb403bb7..222fd55181 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
@@ -20,6 +20,7 @@ class ReadBolusStatePacket(injector: HasAndroidInjector) : MedtrumPacket(injecto
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
+ // TODO: Handle bolus data here
bolusData = data.copyOfRange(RESP_BOLUS_DATA_START, data.size)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
index 3524eda324..3c7f077dc2 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
@@ -1,14 +1,17 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.SYNCHRONIZE
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
+import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
- var state: Int = 0
- var dataFieldsPresent: Int = 0
- var syncData: ByteArray = byteArrayOf()
+ @Inject lateinit var medtrumPump: MedtrumPump
companion object {
@@ -17,6 +20,10 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
private const val RESP_FIELDS_START = 7
private const val RESP_FIELDS_END = RESP_FIELDS_START + 2
private const val RESP_SYNC_DATA_START = 9
+
+ private const val MASK_SUSPEND = 0x01
+ private const val MASK_NORMAL_BOLUS = 0x02
+ private const val MASK_EXTENDED_BOLUS = 0x04
}
init {
@@ -27,9 +34,36 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- state = data.copyOfRange(RESP_STATE_START, RESP_STATE_END).toInt()
- dataFieldsPresent = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
- syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)
+ var state = MedtrumPumpState.fromByte(data[RESP_STATE_START])
+
+ medtrumPump.pumpState = state
+
+ var fieldMask = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
+ var syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)
+ var offset = 0
+
+ if (fieldMask != 0) {
+ aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: fieldMask: $fieldMask")
+ }
+
+ // Remove bolus fields from fieldMask if fields are present
+ // TODO: Test if this workaround is needed (hence the warning log)
+ if (fieldMask and MASK_SUSPEND != 0) {
+ offset += 4 // If field is present, skip 4 bytes
+ }
+ if (fieldMask and MASK_NORMAL_BOLUS != 0) {
+ aapsLogger.warn(LTag.PUMPCOMM, "SynchronizePacket: Normal bolus present removing from fieldMask")
+ fieldMask = fieldMask and MASK_NORMAL_BOLUS.inv()
+ syncData = syncData.copyOfRange(0, offset) + syncData.copyOfRange(offset + 3, syncData.size)
+ }
+ if (fieldMask and MASK_EXTENDED_BOLUS != 0) {
+ aapsLogger.warn(LTag.PUMPCOMM, "SynchronizePacket: Extended bolus present removing from fieldMask")
+ fieldMask = fieldMask and MASK_EXTENDED_BOLUS.inv()
+ syncData = syncData.copyOfRange(0, offset) + syncData.copyOfRange(offset + 3, syncData.size)
+ }
+
+ // Let the notification packet handle the rest of the sync data
+ NotificationPacket(injector).handleMaskedMessage(fieldMask.toByteArray(2) + syncData)
}
return success
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
index 893030c6c2..393a208d06 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
@@ -7,8 +7,10 @@ import info.nightscout.pump.medtrum.comm.packets.AuthorizePacket
import info.nightscout.pump.medtrum.comm.packets.CancelBolusPacket
import info.nightscout.pump.medtrum.comm.packets.CancelTempBasalPacket
import info.nightscout.pump.medtrum.comm.packets.GetDeviceTypePacket
+import info.nightscout.pump.medtrum.comm.packets.GetRecordPacket
import info.nightscout.pump.medtrum.comm.packets.GetTimePacket
import info.nightscout.pump.medtrum.comm.packets.MedtrumPacket
+import info.nightscout.pump.medtrum.comm.packets.NotificationPacket
import info.nightscout.pump.medtrum.comm.packets.PollPatchPacket
import info.nightscout.pump.medtrum.comm.packets.PrimePacket
import info.nightscout.pump.medtrum.comm.packets.ReadBolusStatePacket
@@ -31,8 +33,10 @@ abstract class MedtrumCommModule {
@ContributesAndroidInjector abstract fun contributesCancelBolusPacket(): CancelBolusPacket
@ContributesAndroidInjector abstract fun contributesCancelTempBasalPacket(): CancelTempBasalPacket
@ContributesAndroidInjector abstract fun contributesGetDeviceTypePacket(): GetDeviceTypePacket
+ @ContributesAndroidInjector abstract fun contributesGetRecordPacket(): GetRecordPacket
@ContributesAndroidInjector abstract fun contributesGetTimePacket(): GetTimePacket
@ContributesAndroidInjector abstract fun contributesMedtrumPacket(): MedtrumPacket
+ @ContributesAndroidInjector abstract fun contributesNotificationPacket(): NotificationPacket
@ContributesAndroidInjector abstract fun contributesPollPatchPacket(): PollPatchPacket
@ContributesAndroidInjector abstract fun contributesPrimePacket(): PrimePacket
@ContributesAndroidInjector abstract fun contributesReadBolusStatePacket(): ReadBolusStatePacket
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index f1b6e1e280..0f958790c8 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -92,6 +92,7 @@ class BLEComm @Inject internal constructor(
var isConnected = false // TODO: These may be removed have no function
var isConnecting = false// TODO: These may be removed have no function
+ private var retryCounter = 0
private var uartWrite: BluetoothGattCharacteristic? = null
private var uartRead: BluetoothGattCharacteristic? = null
@@ -158,6 +159,7 @@ class BLEComm @Inject internal constructor(
}
mDeviceSN = deviceSN
isConnecting = true
+ retryCounter = 0
startScan()
return true
}
@@ -374,11 +376,20 @@ class BLEComm @Inject internal constructor(
mBluetoothGatt?.discoverServices()
}, WRITE_DELAY_MILLIS)
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
- close()
- isConnected = false
- isConnecting = false
- mCallback?.onBLEDisconnected()
- aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
+ if (status == 133 && isConnecting && retryCounter < 3) {
+ // Special case for status 133 when we are connecting
+ // We need to close gatt and try to reconnect
+ aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange status 133")
+ close()
+ startScan()
+ retryCounter++
+ } else {
+ close()
+ isConnected = false
+ isConnecting = false
+ mCallback?.onBLEDisconnected()
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnectedS
+ }
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index faea212261..864c4f7c82 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -17,6 +17,8 @@ import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.medtrum.MedtrumPlugin
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.comm.packets.*
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
@@ -50,6 +52,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
@Inject lateinit var commandQueue: CommandQueue
@Inject lateinit var context: Context
@Inject lateinit var medtrumPlugin: MedtrumPlugin
+ @Inject lateinit var medtrumPump: MedtrumPump
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var uiInteraction: UiInteraction
@@ -72,6 +75,29 @@ class MedtrumService : DaggerService(), BLECommCallback {
// TODO: Stuff like this in a settings class?
private var mLastDeviceTime: Long = 0
+ companion object {
+
+ private val MASK_SUSPEND = 0x01
+ private val MASK_NORMAL_BOLUS = 0x02
+ private val MASK_EXTENDED_BOLUS = 0x04
+ private val MASK_BASAL = 0x08
+
+ private val MASK_SETUP = 0x10
+ private val MASK_RESERVOIR = 0x20
+ private val MASK_LIFE_TIME = 0x40
+ private val MASK_BATTERY = 0x80
+
+ private val MASK_STORAGE = 0x100
+ private val MASK_ALARM = 0x200
+ private val MASK_START_TIME = 0x400
+ private val MASK_UNKNOWN_1 = 0x800
+
+ private val MASK_UNUSED_CGM = 0x1000
+ private val MASK_UNUSED_COMMAND_CONFIRM = 0x2000
+ private val MASK_UNUSED_AUTO_STATUS = 0x4000
+ private val MASK_UNUSED_LEGACY = 0x8000
+ }
+
override fun onCreate() {
super.onCreate()
bleComm.setCallback(this)
@@ -182,7 +208,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onNotification(notification: ByteArray) {
aapsLogger.debug(LTag.PUMPCOMM, "<<<<< onNotification" + notification.contentToString())
- // TODO
+ NotificationPacket(injector).handleNotification(notification)
}
override fun onIndication(indication: ByteArray) {
@@ -315,15 +341,14 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
- mLastDeviceTime = (mPacket as GetTimePacket).time
val currTimeSec = dateUtil.nowWithoutMilliseconds() / 1000
- if (abs(timeUtil.convertPumpTimeToSystemTimeSeconds(mLastDeviceTime) - currTimeSec) <= 5) { // Allow 5 sec deviation
+ if (abs(timeUtil.convertPumpTimeToSystemTimeSeconds(medtrumPump.lastTimeReceivedFromPump) - currTimeSec) <= 5) { // Allow 5 sec deviation
toState(SynchronizeState())
} else {
aapsLogger.debug(
LTag.PUMPCOMM,
- "GetTimeState.onIndication need to set time. systemTime: $currTimeSec PumpTime: $mLastDeviceTime Pump Time to system time: " + timeUtil.convertPumpTimeToSystemTimeSeconds(
- mLastDeviceTime
+ "GetTimeState.onIndication need to set time. systemTime: $currTimeSec PumpTime: ${medtrumPump.lastTimeReceivedFromPump} Pump Time to system time: " + timeUtil.convertPumpTimeToSystemTimeSeconds(
+ medtrumPump.lastTimeReceivedFromPump
)
)
toState(SetTimeState())
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
index 4ea715a677..4fff76bc90 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
@@ -4,6 +4,7 @@ import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -13,8 +14,9 @@ class GetTimePacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is GetTimePacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
}
}
}
@@ -46,7 +48,7 @@ class GetTimePacketTest : MedtrumTestBase() {
// Expected values
assertEquals(true, result)
assertEquals(false, packet.failed)
- assertEquals(time, packet.time)
+ assertEquals(MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(time), medtrumPump.lastTimeReceivedFromPump)
}
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
@@ -63,6 +65,6 @@ class GetTimePacketTest : MedtrumTestBase() {
// Expected values
assertEquals(false, result)
assertEquals(true, packet.failed)
- assertEquals(0, packet.time)
+ assertEquals(0, medtrumPump.lastTimeReceivedFromPump)
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacketTest.kt
index 33fb7ff2b1..0c6bf53ac9 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacketTest.kt
@@ -9,7 +9,7 @@ import org.junit.Assert.*
class MedtrumPacketTest : MedtrumTestBase() {
- /** Test base behavoir of the medtrum packet, thse */
+ /** Test base behavoir of the medtrum packet */
private val packetInjector = HasAndroidInjector {
AndroidInjector {
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacketTest.kt
new file mode 100644
index 0000000000..8019981ebb
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacketTest.kt
@@ -0,0 +1,39 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
+import info.nightscout.pump.medtrum.extension.toByteArray
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class NotificationPacketTest : MedtrumTestBase() {
+
+ /** Test base behavoir of the Notification packet */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is NotificationPacket) {
+ it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
+ }
+ }
+ }
+
+ @Test fun handleNotificationGivenStatusAndDataThenStateSaved() {
+ // Inputs
+ val state: Byte = 1
+
+ // Call
+ NotificationPacket(packetInjector).handleNotification(byteArrayOf(state))
+
+ // Expected values
+ assertEquals(medtrumPump.pumpState, MedtrumPumpState.fromByte(state))
+ }
+
+ @Test fun handleMaskedMessageGivenMaskAndDataThenDataSaved() {
+ // TODO: Implement
+ assertTrue(false)
+ }
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
index 121f51b3a6..2250202bf1 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
@@ -13,8 +13,13 @@ class SynchronizePacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is SynchronizePacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
+ }
+ if (it is NotificationPacket) {
+ it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
}
}
}
@@ -36,10 +41,10 @@ class SynchronizePacketTest : MedtrumTestBase() {
// Inputs
val opCode = 3
val responseCode = 0
- val state = 1
+ val state: Byte = 1
val dataFieldsPresent = 4046
- val syncData = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
- val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + state.toByteArray(1) + dataFieldsPresent.toByteArray(2) + syncData
+ val syncData = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42)
+ val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + state + dataFieldsPresent.toByteArray(2) + syncData
// Call
val packet = SynchronizePacket(packetInjector)
@@ -48,9 +53,8 @@ class SynchronizePacketTest : MedtrumTestBase() {
// Expected values
assertEquals(true, result)
assertEquals(false, packet.failed)
- assertEquals(state, packet.state)
- assertEquals(dataFieldsPresent, packet.dataFieldsPresent)
- assertEquals(syncData.contentToString(), packet.syncData.contentToString())
+ assertEquals(state, packet.medtrumPump.pumpState.state)
+ // TODO: Maybe test cutting behavoir
}
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
From fff833dae32128794af376b7a164c38eaf585dbd Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 11 Apr 2023 15:43:29 +0200
Subject: [PATCH 016/116] Patch activation flow
---
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 34 ++++-
.../nightscout/pump/medtrum/MedtrumPump.kt | 44 +++---
.../nightscout/pump/medtrum/code/PatchStep.kt | 5 +-
.../medtrum/comm/enums/MedtrumPumpState.kt | 2 +-
.../medtrum/comm/packets/ActivatePacket.kt | 17 ++-
.../medtrum/comm/packets/MedtrumPacket.kt | 14 +-
.../comm/packets/NotificationPacket.kt | 23 ++--
.../comm/packets/SetBasalProfilePacket.kt | 38 ++++++
.../medtrum/comm/packets/SynchronizePacket.kt | 5 +-
.../pump/medtrum/di/MedtrumModule.kt | 11 ++
.../pump/medtrum/services/MedtrumService.kt | 128 +++++++++++++-----
.../medtrum/ui/MedtrumActivateFragment.kt | 51 +++++++
.../pump/medtrum/ui/MedtrumActivity.kt | 5 +
.../medtrum/ui/MedtrumAttachPatchFragment.kt | 49 +++++++
.../medtrum/ui/MedtrumOverviewFragment.kt | 10 +-
.../medtrum/ui/MedtrumPreparePatchFragment.kt | 16 ++-
.../pump/medtrum/ui/MedtrumPrimeFragment.kt | 21 ++-
.../medtrum/ui/viewmodel/BaseViewModel.kt | 10 ++
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 24 +++-
.../medtrum/ui/viewmodel/MedtrumViewModel.kt | 113 ++++++++++++----
.../res/layout/fragment_medtrum_activate.xml | 66 +++++++++
.../layout/fragment_medtrum_attach_patch.xml | 66 +++++++++
.../res/layout/fragment_medtrum_prime.xml | 35 ++++-
pump/medtrum/src/main/res/values/strings.xml | 9 ++
.../comm/packets/ActivatePacketTest.kt | 1 +
.../comm/packets/SetBasalProfilePacketTest.kt | 39 ++++++
26 files changed, 720 insertions(+), 116 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateFragment.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumAttachPatchFragment.kt
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_activate.xml
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_attach_patch.xml
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index e264320ba5..66833b1f94 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -8,6 +8,7 @@ import android.os.IBinder
import dagger.android.HasAndroidInjector
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Profile
@@ -33,6 +34,7 @@ import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit
import info.nightscout.rx.events.EventAppInitialized
+import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.logging.AAPSLogger
@@ -170,11 +172,33 @@ class MedtrumPlugin @Inject constructor(
}
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
- return PumpEnactResult(injector).success(true).enacted(true) // TODO
+ // New profile will be set when patch is activated
+ if (!isInitialized()) return PumpEnactResult(injector).success(true).enacted(true)
+
+ return if (medtrumService?.updateBasalsInPump(profile) == true) {
+ rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE))
+ uiInteraction.addNotificationValidFor(Notification.PROFILE_SET_OK, rh.gs(info.nightscout.core.ui.R.string.profile_set_ok), Notification.INFO, 60)
+ PumpEnactResult(injector).success(true).enacted(true)
+ } else {
+ uiInteraction.addNotification(Notification.FAILED_UPDATE_PROFILE, rh.gs(info.nightscout.core.ui.R.string.failed_update_basal_profile), Notification.URGENT)
+ PumpEnactResult(injector)
+ }
}
override fun isThisProfileSet(profile: Profile): Boolean {
- return false // TODO
+ if (!isInitialized()) return true
+ var result = false
+ val profileBytes = medtrumPump.buildMedtrumProfileArray(profile)
+ if (profileBytes?.size == medtrumPump.actualBasalProfile.size) {
+ result = true
+ for (i in profileBytes.indices) {
+ if (profileBytes[i] != medtrumPump.actualBasalProfile[i]) {
+ result = false
+ break
+ }
+ }
+ }
+ return result
}
override fun lastDataTime(): Long {
@@ -204,12 +228,14 @@ class MedtrumPlugin @Inject constructor(
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
aapsLogger.info(LTag.PUMP, "setTempBasalPercent - percent: $percent, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
- return PumpEnactResult(injector) // TODO
+ return PumpEnactResult(injector).success(false).enacted(false)
+ .comment("Medtrum driver does not support percentage temp basals")
}
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
aapsLogger.info(LTag.PUMP, "setExtendedBolus - insulin: $insulin, durationInMinutes: $durationInMinutes")
- return PumpEnactResult(injector) // TODO
+ return PumpEnactResult(injector).success(false).enacted(false)
+ .comment("Medtrum driver does not support extended boluses")
}
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 6bda29514f..0536be865c 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -1,5 +1,7 @@
package info.nightscout.pump.medtrum
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.profile.Profile
@@ -14,6 +16,8 @@ import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.round
@@ -26,29 +30,37 @@ class MedtrumPump @Inject constructor(
private val instantiator: Instantiator
) {
- enum class PatchActivationState(val state: Int) {
- NONE(0),
- IDLE(1),
- ACTIVATING(2),
- ACTIVATED(3),
- DEACTIVATING(4),
- DEACTIVATED(5),
- ERROR(6)
- }
+ // Pump state flow
+ // TODO We might want to save this in SP, or at least get activated state from SP
+ private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
+ val pumpStateFlow: StateFlow = _pumpState
- // Pump state and parameters
- var pumpState = MedtrumPumpState.NONE // TODO save in SP
- var patchActivationState = PatchActivationState.NONE // TODO save in SP
+ var pumpState: MedtrumPumpState
+ get() = _pumpState.value
+ set(value) {
+ _pumpState.value = value
+ }
+ // Prime progress as state flow
+ private val _primeProgress = MutableStateFlow(0)
+ val primeProgressFlow: StateFlow = _primeProgress
+
+ var primeProgress: Int
+ get() = _primeProgress.value
+ set(value) {
+ _primeProgress.value = value
+ }
+
+ // TODO: Save this in SP? This might be a bit tricky as we only know what we have set, not what the pump has set but the pump should not change it, addtionally we should track the active basal profile in pump e.g. Basal patern A, B etc
+ var actualBasalProfile = byteArrayOf(0)
var patchId = 0L
var lastKnownSequenceNumber = 0
var lastTimeReceivedFromPump = 0L // Time in seconds!
var suspendTime = 0L // Time in seconds!
var patchStartTime = 0L // Time in seconds!
var patchAge = 0L // Time in seconds!
-
+
var reservoir = 0.0
- var primeProgress = 0
var batteryVoltage_A = 0.0
var batteryVoltage_B = 0.0
@@ -67,7 +79,6 @@ class MedtrumPump @Inject constructor(
var lastStopSequence = 0
var lastStopPatchId = 0
-
// TODO set these setting on init
// User settings (desired values, to be set on pump)
var desiredPatchExpiration = false
@@ -75,7 +86,6 @@ class MedtrumPump @Inject constructor(
var desiredHourlyMaxInsulin: Int = 40
var desiredDailyMaxInsulin: Int = 180
-
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
val list = nsProfile.getBasalValues()
var basals = byteArrayOf()
@@ -87,7 +97,7 @@ class MedtrumPump @Inject constructor(
return null
}
basals += ((rate shl 12) + time).toByteArray(3)
- aapsLogger.debug(LTag.PUMP, "buildMedtrumProfileArray: value: ${item.value} time: ${item.timeAsSeconds}")
+ aapsLogger.debug(LTag.PUMP, "buildMedtrumProfileArray: value: ${item.value} time: ${item.timeAsSeconds}, converted: $rate, $time")
}
return (list.size).toByteArray(1) + basals
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
index 3b2c973ae6..8d615dd713 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
@@ -8,9 +8,8 @@ enum class PatchStep {
DISCARDED_FROM_ALARM,
PREPARE_PATCH,
PRIME,
- ATTACH_INSERT_NEEDLE,
- BASAL_SCHEDULE,
- CHECK_CONNECTION,
+ ATTACH_PATCH,
+ ACTIVATE,
CANCEL,
COMPLETE,
BACK_TO_HOME,
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
index e861c8866a..b52b9c1793 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/MedtrumPumpState.kt
@@ -3,7 +3,7 @@ package info.nightscout.pump.medtrum.comm.enums
enum class MedtrumPumpState(val state: Byte) {
NONE(0),
IDLE(1),
- FILL(2),
+ FILLED(2),
PRIMING(3),
PRIMED(4),
EJECTING(5),
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
index 5911d09525..4e70df0638 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
@@ -57,14 +57,23 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
* bytes 15 - end // Basal profile > see MedtrumPump
*/
+ val autoSuspendEnable: Byte = 0
+ val autoSuspendTime: Byte = 12 // Not sure why, but pump needs this in order to activate
+
val patchExpiration: Byte = medtrumPump.desiredPatchExpiration.toByte()
val alarmSetting: Byte = medtrumPump.desiredAlarmSetting
+
+ val lowSuspend: Byte = 0
+ val predictiveLowSuspend: Byte = 0
+ val predictiveLowSuspendRange: Byte = 30 // Not sure why, but pump needs this in order to activate
+
val hourlyMaxInsulin: Int = round(medtrumPump.desiredHourlyMaxInsulin / 0.05).toInt()
val dailyMaxInsulin: Int = round(medtrumPump.desiredDailyMaxInsulin / 0.05).toInt()
val currentTDD: Double = tddCalculator.calculateToday()?.totalAmount?.div(0.05) ?: 0.0
- return byteArrayOf(opCode) + 0.toByteArray(2) + patchExpiration + alarmSetting + 0.toByteArray(3) + hourlyMaxInsulin.toByteArray(2) + dailyMaxInsulin.toByteArray(2) + currentTDD.toInt()
- .toByteArray(2) + 1.toByte() + basalProfile
+ return byteArrayOf(opCode) + autoSuspendEnable + autoSuspendTime + patchExpiration + alarmSetting + lowSuspend + predictiveLowSuspend + predictiveLowSuspendRange + hourlyMaxInsulin.toByteArray(
+ 2
+ ) + dailyMaxInsulin.toByteArray(2) + currentTDD.toInt().toByteArray(2) + 1.toByte() + basalProfile
}
override fun handleResponse(data: ByteArray): Boolean {
@@ -82,7 +91,9 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
medtrumPump.patchId = patchId
medtrumPump.lastTimeReceivedFromPump = time
- // TODO: Handle basal here, and report to AAPS directly
+ // Update the actual basal profile
+ medtrumPump.actualBasalProfile = basalProfile
+ // TODO: Handle history entry
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt
index 605c071fad..6386e988ef 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt
@@ -30,13 +30,13 @@ open class MedtrumPacket(protected var injector: HasAndroidInjector) {
}
open fun getRequest(): ByteArray {
- aapsLogger.debug(LTag.PUMPCOMM, "Get REQUEST TEST")
return byteArrayOf(opCode)
}
/** handles a response from the Medtrum pump, returns true if command was successfull, returns false if command failed or waiting for response */
open fun handleResponse(data: ByteArray): Boolean {
- if (expectedMinRespLength > data.size) {
+ // Check for broken packets
+ if (RESP_RESULT_END > data.size) {
failed = true
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected response length, expected: $expectedMinRespLength got: ${data.size}")
return false
@@ -48,11 +48,17 @@ open class MedtrumPacket(protected var injector: HasAndroidInjector) {
return when {
incomingOpCode != opCode -> {
failed = true
- aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected command, expected: $opCode got: $incomingOpCode")
+ aapsLogger.error(LTag.PUMPCOMM, "handleResponse: Unexpected command, expected: $opCode got: $incomingOpCode")
false
}
responseCode == 0 -> {
+ // Check if length is what is expected from this type of packet
+ if (expectedMinRespLength > data.size) {
+ failed = true
+ aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected response length, expected: $expectedMinRespLength got: ${data.size}")
+ return false
+ }
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Happy command: $opCode response: $responseCode")
true
}
@@ -65,7 +71,7 @@ open class MedtrumPacket(protected var injector: HasAndroidInjector) {
else -> {
failed = true
- aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Error in command: $opCode response: $responseCode")
+ aapsLogger.warn(LTag.PUMPCOMM, "handleResponse: Error in command: $opCode response: $responseCode")
false
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index 6cb5a5bfa6..88f9f2bf70 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -14,19 +14,19 @@ import kotlin.experimental.and
class NotificationPacket(val injector: HasAndroidInjector) {
- /**
+ /**
* This is a bit of a special packet, as it is not a command packet
* but a notification packet. It is sent by the pump to the phone
* when the pump has a notification to send.
- *
+ *
* Notifications are sent regualary, regardless of the pump state.
- *
+ *
* There can be multiple messages in one packet, this is noted by the fieldMask.
- *
+ *
* Byte 1: State (Handle a state change directly? before analyzing further?)
* Byte 2-3: FieldMask (BitMask which tells the fields present in the message)
* Byte 4-end : status data
- *
+ *
* When multiple fields are in the message, the data is concatenated.
* This kind of message can also come as a response of SynchronizePacket,
* and can be handled here by handleMaskedMessage() as well.
@@ -36,9 +36,10 @@ class NotificationPacket(val injector: HasAndroidInjector) {
@Inject lateinit var medtrumPump: MedtrumPump
companion object {
+
private const val NOTIF_STATE_START = 0
private const val NOTIF_STATE_END = NOTIF_STATE_START + 1
-
+
private const val MASK_SUSPEND = 0x01
private const val MASK_NORMAL_BOLUS = 0x02
private const val MASK_EXTENDED_BOLUS = 0x04
@@ -79,7 +80,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
/**
* Handle a message with a field mask, can be used by other packets as well
*/
- fun handleMaskedMessage(data: ByteArray) {
+ fun handleMaskedMessage(data: ByteArray) {
val fieldMask = data.copyOfRange(0, 2).toInt()
var offset = 2
@@ -96,13 +97,13 @@ class NotificationPacket(val injector: HasAndroidInjector) {
aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
var bolusType = bolusData and 0x7F
- var bolusCompleted = (bolusData shr 7) and 0x01
+ var bolusCompleted = (bolusData shr 7) and 0x01 // TODO: Check for other flags here :)
var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() / 0.05
// TODO Sync bolus flow:
// If bolus is known add status
// If bolus is not known start read bolus
// When bolus is completed, remove bolus from medtrumPump
- aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
+ aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolusData: $bolusData bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
offset += 3
}
@@ -172,7 +173,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
medtrumPump.alarmFlags = data.copyOfRange(offset, offset + 2).toInt()
medtrumPump.alarmParameter = data.copyOfRange(offset + 2, offset + 4).toInt()
aapsLogger.debug(LTag.PUMPCOMM, "Alarm flags: ${medtrumPump.alarmFlags}, alarm parameter: ${medtrumPump.alarmParameter}")
- offset += 4
+ offset += 4
}
if (fieldMask and MASK_START_TIME != 0) {
@@ -202,5 +203,5 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_UNUSED_LEGACY != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Unused legacy notification received, not handled!")
}
- }
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
index 186aa0f463..6023a2fafb 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
@@ -3,18 +3,56 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BASAL_PROFILE
+import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.pump.medtrum.extension.toLong
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import javax.inject.Inject
class SetBasalProfilePacket(injector: HasAndroidInjector, private val basalProfile: ByteArray) : MedtrumPacket(injector) {
@Inject lateinit var medtrumPump: MedtrumPump
+ companion object {
+
+ private const val RESP_BASAL_TYPE_START = 6
+ private const val RESP_BASAL_TYPE_END = RESP_BASAL_TYPE_START + 1
+ private const val RESP_BASAL_VALUE_START = 7
+ private const val RESP_BASAL_VALUE_END = RESP_BASAL_VALUE_START + 2
+ private const val RESP_BASAL_SEQUENCE_START = 9
+ private const val RESP_BASAL_SEQUENCE_END = RESP_BASAL_SEQUENCE_START + 2
+ private const val RESP_BASAL_PATCH_ID_START = 11
+ private const val RESP_BASAL_PATCH_ID_END = RESP_BASAL_PATCH_ID_START + 2
+ private const val RESP_BASAL_START_TIME_START = 13
+ private const val RESP_BASAL_START_TIME_END = RESP_BASAL_START_TIME_START + 4
+ }
+
init {
opCode = SET_BASAL_PROFILE.code
+ expectedMinRespLength = RESP_BASAL_START_TIME_END
+
}
override fun getRequest(): ByteArray {
val basalType: Byte = 1 // Fixed to normal basal
return byteArrayOf(opCode) + basalType + basalProfile
}
+
+ override fun handleResponse(data: ByteArray): Boolean {
+ val success = super.handleResponse(data)
+ if (success) {
+ val medtrumTimeUtil = MedtrumTimeUtil()
+ val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
+ val basalValue = data.copyOfRange(RESP_BASAL_VALUE_START, RESP_BASAL_VALUE_END).toInt() * 0.05
+ val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
+ val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
+ val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+
+ // Update the actual basal profile
+ medtrumPump.actualBasalProfile = basalProfile
+ // TODO: Do we need to let AAPS know? Maybe depends on where we cancel TBR if we need to
+ // TODO: Handle history entry
+ medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime)
+ }
+ return success
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
index 3c7f077dc2..71b022e848 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
@@ -37,7 +37,7 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
var state = MedtrumPumpState.fromByte(data[RESP_STATE_START])
medtrumPump.pumpState = state
-
+
var fieldMask = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
var syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)
var offset = 0
@@ -46,8 +46,7 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: fieldMask: $fieldMask")
}
- // Remove bolus fields from fieldMask if fields are present
- // TODO: Test if this workaround is needed (hence the warning log)
+ // Remove bolus fields from fieldMask if fields are present (we sync bolus trough other commands)
if (fieldMask and MASK_SUSPEND != 0) {
offset += 4 // If field is present, skip 4 bytes
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
index 18f4fb7419..9b5548b746 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
@@ -7,6 +7,8 @@ import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoMap
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumActivateFragment
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
import info.nightscout.pump.medtrum.services.MedtrumService
@@ -56,6 +58,14 @@ abstract class MedtrumModule {
@ContributesAndroidInjector
internal abstract fun contributesPrimeFragment(): MedtrumPrimeFragment
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesAttachPatchFragment(): MedtrumAttachPatchFragment
+
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesActivateFragment(): MedtrumActivateFragment
+
// ACTIVITIES
@ContributesAndroidInjector
abstract fun contributesMedtrumActivity(): MedtrumActivity
@@ -63,4 +73,5 @@ abstract class MedtrumModule {
// SERVICE
@ContributesAndroidInjector
abstract fun contributesMedtrumService(): MedtrumService
+
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 864c4f7c82..68fe0fd3a8 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -34,6 +34,7 @@ import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
+import info.nightscout.shared.utils.T
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.util.*
@@ -75,29 +76,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
// TODO: Stuff like this in a settings class?
private var mLastDeviceTime: Long = 0
- companion object {
-
- private val MASK_SUSPEND = 0x01
- private val MASK_NORMAL_BOLUS = 0x02
- private val MASK_EXTENDED_BOLUS = 0x04
- private val MASK_BASAL = 0x08
-
- private val MASK_SETUP = 0x10
- private val MASK_RESERVOIR = 0x20
- private val MASK_LIFE_TIME = 0x40
- private val MASK_BATTERY = 0x80
-
- private val MASK_STORAGE = 0x100
- private val MASK_ALARM = 0x200
- private val MASK_START_TIME = 0x400
- private val MASK_UNKNOWN_1 = 0x800
-
- private val MASK_UNUSED_CGM = 0x1000
- private val MASK_UNUSED_COMMAND_CONFIRM = 0x2000
- private val MASK_UNUSED_AUTO_STATUS = 0x4000
- private val MASK_UNUSED_LEGACY = 0x8000
- }
-
override fun onCreate() {
super.onCreate()
bleComm.setCallback(this)
@@ -135,6 +113,18 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
+ fun startPrime(): Boolean {
+ val packet = PrimePacket(injector)
+ return sendPacketAndGetResponse(packet)
+ }
+
+ fun startActivate(): Boolean {
+ // TODO not sure this is the correct way lol, We might need to tell AAPS which profile is active
+ val profile = profileFunction.getProfile()?.let { medtrumPump.buildMedtrumProfileArray(it) }
+ val packet = profile?.let { ActivatePacket(injector, it) }
+ return packet?.let { sendPacketAndGetResponse(it) } == true
+ }
+
fun stopConnecting() {
// TODO proper way for this might need send commands etc
bleComm.stopConnecting()
@@ -177,9 +167,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun updateBasalsInPump(profile: Profile): Boolean {
- if (!isConnected) return false
- // TODO
- return false
+ val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
+ return packet?.let { sendPacketAndGetResponse(it) } == true
}
fun changePump() {
@@ -189,11 +178,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
} catch (e: NumberFormatException) {
aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
}
- // TODO: What do we do with active patch here?
+ // TODO: What do we do with active patch here? Getting status should be enough?
when (currentState) {
- // is IdleState -> connect("changePump")
+ is IdleState -> connect("changePump")
// is ReadyState -> disconnect("changePump")
- else -> null // TODO: What to do here? Abort stuff?
+ else -> null // TODO: What to do here? Abort stuff?
}
}
@@ -244,6 +233,19 @@ class MedtrumService : DaggerService(), BLECommCallback {
currentState.onEnter()
}
+ private fun sendPacketAndGetResponse(packet: MedtrumPacket): Boolean {
+ var result = false
+ if (currentState is ReadyState) {
+ toState(CommandState())
+ mPacket = packet
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ result = currentState.waitForResponse()
+ } else {
+ aapsLogger.error(LTag.PUMPCOMM, "Send packet attempt when in non Ready state")
+ }
+ return result
+ }
+
// State class, Can we move this to different file?
private abstract inner class State {
@@ -265,11 +267,18 @@ class MedtrumService : DaggerService(), BLECommCallback {
// TODO: Check flow for this
toState(IdleState())
}
+
+ open fun waitForResponse(): Boolean {
+ return false
+ }
}
private inner class IdleState : State() {
- override fun onEnter() {}
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached IdleState")
+ connect("IdleState onEnter")
+ }
override fun onConnected() {
super.onConnected()
@@ -278,10 +287,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onDisconnected() {
super.onDisconnected()
- // TODO replace this by proper connecting state where we can retry
+ connect("IdleState onDisconnected")
}
}
+ // State for connect flow, could be replaced by commandState and steps in connect()
private inner class AuthState : State() {
override fun onEnter() {
@@ -306,6 +316,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
+ // State for connect flow, could be replaced by commandState and steps in connect()
private inner class GetDeviceTypeState : State() {
override fun onEnter() {
@@ -330,6 +341,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
+ // State for connect flow, could be replaced by commandState and steps in connect()
private inner class GetTimeState : State() {
override fun onEnter() {
@@ -361,6 +373,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
+ // State for connect flow, could be replaced by commandState and steps in connect()
private inner class SetTimeState : State() {
override fun onEnter() {
@@ -381,6 +394,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
+ // State for connect flow, could be replaced by commandState and steps in connect()
private inner class SetTimeZoneState : State() {
override fun onEnter() {
@@ -401,6 +415,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
+ // State for connect flow, could be replaced by commandState and steps in connect()
private inner class SynchronizeState : State() {
override fun onEnter() {
@@ -422,6 +437,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
+ // State for connect flow, could be replaced by commandState and steps in connect()
private inner class SubscribeState : State() {
override fun onEnter() {
@@ -442,6 +458,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
+ // This state is reached when the patch is ready to receive commands (Activation, Bolus, temp basal and whatever)
private inner class ReadyState : State() {
override fun onEnter() {
@@ -451,6 +468,53 @@ class MedtrumService : DaggerService(), BLECommCallback {
isConnected = true
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
}
- // Just a placeholder, this state is reached when the patch is ready to receive commands (Bolus, temp basal and whatever)
+ }
+
+ // This state is when a command is send and we wait for a response for that command
+ private inner class CommandState : State() {
+
+ private var responseHandled = false
+ private var responseSuccess = false
+
+ override fun onEnter() {
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached CommandState")
+ }
+
+ override fun onIndication(data: ByteArray) {
+ if (mPacket?.handleResponse(data) == true) {
+ // Succes!
+ responseHandled = true
+ responseSuccess = true
+ toState(ReadyState())
+ } else if (mPacket?.failed == true) {
+ // Failure
+ responseHandled = true
+ responseSuccess = false
+ toState(ReadyState())
+ }
+ }
+
+ override fun onDisconnected() {
+ super.onDisconnected()
+ responseHandled = true
+ responseSuccess = false
+ }
+
+ override fun waitForResponse(): Boolean {
+ val startTime = System.currentTimeMillis()
+ val timeoutMillis = T.secs(45).msecs()
+ while (!responseHandled) {
+ if (System.currentTimeMillis() - startTime > timeoutMillis) {
+ // If we haven't received a response in the specified time, assume the command failed
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service CommandState timeout")
+ // Disconnect to cancel any outstanding commands and go back to ready state
+ bleComm.disconnect("Timeout")
+ toState(ReadyState())
+ return false
+ }
+ Thread.sleep(100)
+ }
+ return responseSuccess
+ }
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateFragment.kt
new file mode 100644
index 0000000000..ab788b9d4b
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateFragment.kt
@@ -0,0 +1,51 @@
+package info.nightscout.androidaps.plugins.pump.eopatch.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumActivateBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumActivateFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumActivateFragment = MedtrumActivateFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_activate
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.PRIMED -> Unit // Nothing to do here, previous state
+ MedtrumViewModel.SetupStep.ACTIVATED -> btnPositive.visibility = View.VISIBLE
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error Activating") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+
+ else -> {
+ ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+ }
+ }
+ startActivate()
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
index 7b49049a6e..1c0edd9f94 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
@@ -9,6 +9,8 @@ import android.os.Bundle
import android.view.MotionEvent
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.ViewModelProvider
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumActivateFragment
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
import info.nightscout.core.utils.extensions.safeGetSerializableExtra
@@ -42,6 +44,9 @@ class MedtrumActivity : MedtrumBaseActivity() {
when (it) {
PatchStep.PREPARE_PATCH -> setupViewFragment(MedtrumPreparePatchFragment.newInstance())
PatchStep.PRIME -> setupViewFragment(MedtrumPrimeFragment.newInstance())
+ PatchStep.ATTACH_PATCH -> setupViewFragment(MedtrumAttachPatchFragment.newInstance())
+ PatchStep.ACTIVATE -> setupViewFragment(MedtrumActivateFragment.newInstance())
+ PatchStep.COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
PatchStep.CANCEL -> this@MedtrumActivity.finish()
else -> Unit
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumAttachPatchFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumAttachPatchFragment.kt
new file mode 100644
index 0000000000..b8741413b7
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumAttachPatchFragment.kt
@@ -0,0 +1,49 @@
+package info.nightscout.androidaps.plugins.pump.eopatch.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumAttachPatchBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumAttachPatchFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumAttachPatchFragment = MedtrumAttachPatchFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_attach_patch
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ aapsLogger.debug(LTag.PUMP, "MedtrumAttachPatchFragment onViewCreated")
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.PRIMED -> Unit // Nothing to do here, previous state
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error attach patch") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+ else -> {
+ ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index 25aad5ce89..3ee8141993 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -6,6 +6,7 @@ import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.ViewModelProvider
+import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumOverviewBinding
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
import info.nightscout.pump.medtrum.R
@@ -13,6 +14,7 @@ import info.nightscout.pump.medtrum.code.EventType
import info.nightscout.pump.medtrum.code.PatchStep
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
import io.reactivex.rxjava3.disposables.CompositeDisposable
import javax.inject.Inject
@@ -20,6 +22,7 @@ class MedtrumOverviewFragment : MedtrumBaseFragment
private lateinit var resultLauncherForPause: ActivityResultLauncher
@@ -40,7 +43,12 @@ class MedtrumOverviewFragment : MedtrumBaseFragment
when (evt.peekContent()) {
- EventType.ACTIVATION_CLICKED -> requireContext().apply { startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.PREPARE_PATCH)) }
+ EventType.ACTIVATION_CLICKED -> requireContext().apply {
+ val step = convertToPatchStep(medtrumPump.pumpState)
+ if (step != PatchStep.PREPARE_PATCH) {
+ aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step")
+ }
+ startActivity(MedtrumActivity.createIntentFromMenu(this, step)) }
else -> Unit
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
index 650d103f6e..d044e82073 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
@@ -3,7 +3,9 @@ package info.nightscout.androidaps.plugins.pump.eopatch.ui
import android.os.Bundle
import android.view.View
import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPreparePatchBinding
import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
@@ -30,9 +32,19 @@ class MedtrumPreparePatchFragment : MedtrumBaseFragment btnPositive.visibility = View.GONE
// TODO: Confirmation dialog
- MedtrumViewModel.SetupStep.CONNECTED -> btnPositive.visibility = View.VISIBLE
- else -> Unit
+ MedtrumViewModel.SetupStep.FILLED -> btnPositive.visibility = View.VISIBLE
+
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error preparing patch") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+
+ else -> {
+ ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
}
}
preparePatch()
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
index 42f27d3105..d0903226b0 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
@@ -3,7 +3,9 @@ package info.nightscout.androidaps.plugins.pump.eopatch.ui
import android.os.Bundle
import android.view.View
import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPrimeBinding
import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
@@ -26,7 +28,24 @@ class MedtrumPrimeFragment : MedtrumBaseFragment()
super.onViewCreated(view, savedInstanceState)
binding.apply {
viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
- // TODO do stuff
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.FILLED -> Unit // Nothing to do here, previous state
+ MedtrumViewModel.SetupStep.PRIMED -> btnPositive.visibility = View.VISIBLE
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error priming") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+
+ else -> {
+ ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+ }
+ }
+ startPrime()
+ }
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
index c3b39693b3..62a214ae3a 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
@@ -1,6 +1,8 @@
package info.nightscout.pump.medtrum.ui.viewmodel
import androidx.lifecycle.ViewModel
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.disposables.Disposable
@@ -28,4 +30,12 @@ abstract class BaseViewModel : ViewModel() {
fun Disposable.addTo() = apply { compositeDisposable.add(this) }
+ fun convertToPatchStep(pumpState: MedtrumPumpState) = when (pumpState) {
+ MedtrumPumpState.NONE, MedtrumPumpState.IDLE -> PatchStep.PREPARE_PATCH
+ MedtrumPumpState.FILLED -> PatchStep.PREPARE_PATCH
+ MedtrumPumpState.PRIMING -> PatchStep.PRIME
+ MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> PatchStep.ATTACH_PATCH
+ MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> PatchStep.COMPLETE
+ else -> PatchStep.CANCEL
+ }
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index d270275c03..2aaddfb663 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -9,6 +9,8 @@ import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
import info.nightscout.pump.medtrum.ui.event.UIEvent
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
import info.nightscout.interfaces.profile.ProfileFunction
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventPumpStatusChanged
@@ -16,6 +18,9 @@ import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import javax.inject.Inject
class MedtrumOverviewViewModel @Inject constructor(
@@ -24,9 +29,11 @@ class MedtrumOverviewViewModel @Inject constructor(
private val aapsSchedulers: AapsSchedulers,
private val fabricPrivacy: FabricPrivacy,
private val profileFunction: ProfileFunction,
+ private val medtrumPump: MedtrumPump
) : BaseViewModel() {
private var disposable: CompositeDisposable = CompositeDisposable()
+ private val scope = CoroutineScope(Dispatchers.Default)
private val _eventHandler = SingleLiveEvent>()
val eventHandler: LiveData>
@@ -36,11 +43,12 @@ class MedtrumOverviewViewModel @Inject constructor(
val bleStatus: LiveData
get() = _bleStatus
- // TODO make these livedata
- val isPatchActivated: Boolean
- get() = false // TODO
+ private val _isPatchActivated = SingleLiveEvent()
+ val isPatchActivated: LiveData
+ get() = _isPatchActivated
init {
+ // TODO proper connection state from medtrumPump
disposable += rxBus
.toObservable(EventPumpStatusChanged::class.java)
.observeOn(aapsSchedulers.main)
@@ -59,6 +67,16 @@ class MedtrumOverviewViewModel @Inject constructor(
""
}
}, fabricPrivacy::logException)
+ scope.launch {
+ medtrumPump.pumpStateFlow.collect { state ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
+ if (state > MedtrumPumpState.EJECTED) {
+ _isPatchActivated.postValue(true)
+ } else {
+ _isPatchActivated.postValue(false)
+ }
+ }
+ }
}
fun onClickActivation() {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
index 328b42a89a..1be28aa66a 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
@@ -4,9 +4,12 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.pump.medtrum.MedtrumPlugin
+import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.services.MedtrumService
import info.nightscout.pump.medtrum.code.EventType
import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
import info.nightscout.pump.medtrum.ui.event.UIEvent
@@ -17,8 +20,9 @@ import info.nightscout.rx.events.EventPumpStatusChanged
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
-import io.reactivex.rxjava3.disposables.CompositeDisposable
-import io.reactivex.rxjava3.kotlin.plusAssign
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import javax.inject.Inject
class MedtrumViewModel @Inject constructor(
@@ -28,17 +32,20 @@ class MedtrumViewModel @Inject constructor(
private val aapsSchedulers: AapsSchedulers,
private val fabricPrivacy: FabricPrivacy,
private val medtrumPlugin: MedtrumPlugin,
+ private val medtrumPump: MedtrumPump,
private val sp: SP
) : BaseViewModel() {
val patchStep = MutableLiveData()
- val title = "Activation"
-
val medtrumService: MedtrumService?
get() = medtrumPlugin.getService()
- private var disposable: CompositeDisposable = CompositeDisposable()
+ private val scope = CoroutineScope(Dispatchers.Default)
+
+ private val _title = MutableLiveData(R.string.step_prepare_patch)
+ val title: LiveData
+ get() = _title
private val _eventHandler = SingleLiveEvent>()
val eventHandler: LiveData>
@@ -47,22 +54,37 @@ class MedtrumViewModel @Inject constructor(
private var mInitPatchStep: PatchStep? = null
init {
- disposable += rxBus
- .toObservable(EventPumpStatusChanged::class.java)
- .observeOn(aapsSchedulers.main)
- .subscribe({
- when (it.status) {
- EventPumpStatusChanged.Status.CONNECTING -> {}
+ scope.launch {
+ medtrumPump.pumpStateFlow.collect { state ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
+ when (state) {
+ MedtrumPumpState.NONE, MedtrumPumpState.IDLE -> {
+ setupStep.postValue(SetupStep.INITIAL)
+ }
- EventPumpStatusChanged.Status.CONNECTED
- -> if (patchStep.value == PatchStep.PREPARE_PATCH) setupStep.postValue(SetupStep.CONNECTED) else {
- }
+ MedtrumPumpState.FILLED -> {
+ setupStep.postValue(SetupStep.FILLED)
+ }
- EventPumpStatusChanged.Status.DISCONNECTED -> {}
+ MedtrumPumpState.PRIMING -> {
+ // setupStep.postValue(SetupStep.PRIMING)
+ // TODO: What to do here? start prime counter?
+ }
- else -> {}
- }
- }, fabricPrivacy::logException)
+ MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> {
+ setupStep.postValue(SetupStep.PRIMED)
+ }
+
+ MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
+ setupStep.postValue(SetupStep.ACTIVATED)
+ }
+
+ else -> {
+ setupStep.postValue(SetupStep.ERROR)
+ }
+ }
+ }
+ }
}
fun moveStep(newPatchStep: PatchStep) {
@@ -71,8 +93,8 @@ class MedtrumViewModel @Inject constructor(
if (oldPatchStep != newPatchStep) {
when (newPatchStep) {
PatchStep.CANCEL -> {
- if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Cancel") else {
- }
+ // if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Cancel") else {
+ // }
}
else -> null
@@ -91,20 +113,49 @@ class MedtrumViewModel @Inject constructor(
}
fun preparePatch() {
- // TODO: Decide if we want to connect already when user is still filling, or if we want to wait after user is done filling
+ // TODO When we dont need to connect what needs to be done here?
medtrumService?.connect("PreparePatch")
}
+ fun startPrime() {
+ // TODO: Get result from service
+ if (medtrumPump.pumpState == MedtrumPumpState.PRIMING) {
+ aapsLogger.info(LTag.PUMP, "startPrime: already priming!")
+ } else {
+ if (medtrumService?.startPrime() == true) {
+ aapsLogger.info(LTag.PUMP, "startPrime: success!")
+ } else {
+ aapsLogger.info(LTag.PUMP, "startPrime: failure!")
+ setupStep.postValue(SetupStep.ERROR)
+ }
+ }
+ }
+
+ fun startActivate() {
+ if (medtrumService?.startActivate() == true) {
+ aapsLogger.info(LTag.PUMP, "startActivate: success!")
+ } else {
+ aapsLogger.info(LTag.PUMP, "startActivate: failure!")
+ setupStep.postValue(SetupStep.ERROR)
+ }
+ }
+
private fun prepareStep(step: PatchStep?): PatchStep {
// TODO Title per screen :) And proper sync with patchstate
- // (step ?: convertToPatchStep(patchConfig.lifecycleEvent.lifeCycle)).let { newStep ->
-
- (step ?: PatchStep.SAFE_DEACTIVATION).let { newStep ->
+ (step ?: convertToPatchStep(medtrumPump.pumpState)).let { newStep ->
when (newStep) {
-
- else -> ""
+ PatchStep.PREPARE_PATCH -> R.string.step_prepare_patch
+ PatchStep.PRIME -> R.string.step_prime
+ PatchStep.ATTACH_PATCH -> R.string.step_attach
+ PatchStep.ACTIVATE -> R.string.step_activate
+ PatchStep.COMPLETE -> R.string.step_complete
+ else -> _title.value
}.let {
-
+ aapsLogger.info(LTag.PUMP, "prepareStep: title before cond: $it")
+ if (_title.value != it) {
+ aapsLogger.info(LTag.PUMP, "prepareStep: title: $it")
+ _title.postValue(it)
+ }
}
patchStep.postValue(newStep)
@@ -114,9 +165,11 @@ class MedtrumViewModel @Inject constructor(
}
enum class SetupStep {
- CONNECTED,
- PRIME_READY,
- ACTIVATED
+ INITIAL,
+ FILLED,
+ PRIMED,
+ ACTIVATED,
+ ERROR
}
val setupStep = MutableLiveData()
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_activate.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_activate.xml
new file mode 100644
index 0000000000..dbf6522fe1
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_activate.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_attach_patch.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_attach_patch.xml
new file mode 100644
index 0000000000..650c2450a0
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_attach_patch.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_prime.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_prime.xml
index cbdb2073e1..b0ce5901b7 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_prime.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_prime.xml
@@ -25,7 +25,40 @@
android:layout_height="wrap_content"
tools:context=".ui.MedtrumActivity">
-
+
+
+
+
+
+
+
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 9ea34ecd97..fc0f73358a 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -16,7 +16,16 @@
Discard/Change Patch
+ Next
Start priming
+ Start activation
+ Complete
+
+ Prepare patch
+ Priming
+ Attach patch
+ Activation
+ Complete
SN
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
index d42b412c78..13f41b0fbc 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
@@ -70,6 +70,7 @@ class ActivatePacketTest : MedtrumTestBase() {
assertEquals(expectedBasalSequence, medtrumPump.lastBasalSequence)
assertEquals(expectedBasalPatchId, medtrumPump.lastBasalPatchId)
assertEquals(expectedBasalStart, medtrumPump.lastBasalStartTime)
+ assertEquals(basalProfile, medtrumPump.actualBasalProfile)
}
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
index 18895facf9..64165f3bd2 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
@@ -32,4 +32,43 @@ class SetBasalProfilePacketTest : MedtrumTestBase() {
val expected = byteArrayOf(opCode.toByte()) + 1.toByte() + basalProfile
assertEquals(expected.contentToString(), result.contentToString())
}
+
+ @Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
+ // Inputs
+ val repsonse = byteArrayOf(18, 21, 16, 0, 0, 0, 1, 22, 0, 3, 0, -110, 0, -32, -18, 88, 17)
+ val basalProfile = byteArrayOf(8, 2, 3, 4, -1, 0, 0, 0, 0)
+
+ // Call
+ val packet = SetBasalProfilePacket(packetInjector, basalProfile)
+ val result = packet.handleResponse(repsonse)
+
+ // Expected values
+ val expectedBasalType = 1
+ val expectedBasalRate = 1.1
+ val expectedBasalSequence = 3
+ val expectedStartTime = 1679575392L
+ val expectedPatchId = 146
+
+ assertTrue(result)
+ assertEquals(expectedBasalType, medtrumPump.lastBasalType)
+ assertEquals(expectedBasalRate, medtrumPump.lastBasalRate, 0.01)
+ assertEquals(expectedBasalSequence, medtrumPump.lastBasalSequence)
+ assertEquals(expectedStartTime, medtrumPump.lastBasalStartTime)
+ assertEquals(expectedPatchId, medtrumPump.lastBasalPatchId)
+ assertEquals(basalProfile, medtrumPump.actualBasalProfile)
+ }
+
+ @Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
+ // Inputs
+ val response = byteArrayOf(18, 21, 16, 0, 0, 0, 1, 22, 0, 3, 0, -110, 0, -32, -18, 88)
+ val basalProfile = byteArrayOf(8, 2, 3, 4, -1, 0, 0, 0, 0)
+
+ // Call
+ val packet = SetBasalProfilePacket(packetInjector, basalProfile)
+ val result = packet.handleResponse(response)
+
+ // Expected values
+ assertFalse(result)
+ assertTrue(packet.failed)
+ }
}
From 61e873dbcc821501459c2117ff25ccccef001af1 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 15 Apr 2023 15:23:26 +0200
Subject: [PATCH 017/116] Deactivation, better connection flow
---
.../interfaces/pump/defs/PumpType.kt | 1 +
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 29 ++-
.../nightscout/pump/medtrum/MedtrumPump.kt | 43 +++--
.../pump/medtrum/code/ConnectionState.kt | 7 +
.../nightscout/pump/medtrum/code/PatchStep.kt | 8 +-
.../medtrum/comm/packets/ActivatePacket.kt | 19 ++
.../medtrum/comm/packets/AuthorizePacket.kt | 10 +-
.../comm/packets/NotificationPacket.kt | 20 +-
.../comm/packets/SetBolusMotorPacket.kt | 1 +
.../medtrum/comm/packets/SynchronizePacket.kt | 2 +
.../pump/medtrum/di/MedtrumModule.kt | 10 +
.../pump/medtrum/encryption/Crypt.kt | 28 ++-
.../pump/medtrum/services/MedtrumService.kt | 71 ++++---
.../pump/medtrum/ui/MedtrumActivity.kt | 22 ++-
.../ui/MedtrumDeactivatePatchFragment.kt | 49 +++++
.../medtrum/ui/MedtrumOverviewFragment.kt | 12 +-
.../ui/MedtrumStartDeactivationFragment.kt | 49 +++++
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 45 +++--
.../medtrum/ui/viewmodel/MedtrumViewModel.kt | 176 +++++++++++++-----
.../fragment_medtrum_deactivate_patch.xml | 66 +++++++
.../fragment_medtrum_start_deactivation.xml | 66 +++++++
pump/medtrum/src/main/res/values/strings.xml | 4 +
.../pump/medtrum/MedtrumTestBase.kt | 4 +-
.../comm/packets/ActivatePacketTest.kt | 3 +-
.../comm/packets/AuthorizePacketTest.kt | 14 +-
25 files changed, 582 insertions(+), 177 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/ConnectionState.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivatePatchFragment.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumStartDeactivationFragment.kt
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_deactivate_patch.xml
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_start_deactivation.xml
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
index 4199af95a8..68dbf1277d 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
@@ -410,6 +410,7 @@ enum class PumpType {
baseBasalSpecialSteps = null,
pumpCapability = PumpCapability.MedtrumCapabilities,
isPatchPump = true,
+ maxReservoirReading = 400,
source = Source.Medtrum
);
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 66833b1f94..9ab782dd7d 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -52,8 +52,7 @@ import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
-@Singleton
-class MedtrumPlugin @Inject constructor(
+@Singleton class MedtrumPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
rh: ResourceHelper,
@@ -81,8 +80,6 @@ class MedtrumPlugin @Inject constructor(
private val disposable = CompositeDisposable()
private var medtrumService: MedtrumService? = null
- private var mPumpType: PumpType = PumpType.MEDTRUM_NANO
- private val mPumpDescription = PumpDescription(mPumpType)
override fun onStart() {
super.onStart()
@@ -120,7 +117,7 @@ class MedtrumPlugin @Inject constructor(
}
override fun isInitialized(): Boolean {
- return medtrumPump.pumpState > MedtrumPumpState.EJECTED
+ return medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED
}
override fun isSuspended(): Boolean {
@@ -132,7 +129,8 @@ class MedtrumPlugin @Inject constructor(
}
override fun isConnected(): Boolean {
- return if (!isInitialized()) true else medtrumService?.isConnected ?: true // This is a workaround to prevent AAPS to trigger connects when we are initializing
+ // This is a workaround to prevent AAPS to trigger connects when we have no patch activated
+ return if (!medtrumPump.patchActivated) true else medtrumService?.isConnected ?: false
}
override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false
@@ -142,7 +140,7 @@ class MedtrumPlugin @Inject constructor(
}
override fun connect(reason: String) {
- if (isInitialized()) {
+ if (medtrumPump.patchActivated) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
aapsLogger.debug(LTag.PUMP, "Medtrum connect - service::$medtrumService")
// aapsLogger.debug(LTag.PUMP, "Medtrum connect - mDeviceSN:$mDeviceSN")
@@ -166,6 +164,7 @@ class MedtrumPlugin @Inject constructor(
}
override fun getPumpStatus(reason: String) {
+ aapsLogger.debug(LTag.PUMP, "Medtrum getPumpStatus - reason:$reason")
if (isInitialized()) {
medtrumService?.readPumpStatus()
}
@@ -202,14 +201,14 @@ class MedtrumPlugin @Inject constructor(
}
override fun lastDataTime(): Long {
- return 0 // TODO
+ return medtrumPump.lastTimeReceivedFromPump * 1000L
}
override val baseBasalRate: Double
get() = 0.0 // TODO
override val reservoirLevel: Double
- get() = 0.0 // TODO
+ get() = medtrumPump.reservoir
override val batteryLevel: Int
get() = 0 // TODO
@@ -228,14 +227,12 @@ class MedtrumPlugin @Inject constructor(
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
aapsLogger.info(LTag.PUMP, "setTempBasalPercent - percent: $percent, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
- return PumpEnactResult(injector).success(false).enacted(false)
- .comment("Medtrum driver does not support percentage temp basals")
+ return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum driver does not support percentage temp basals")
}
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
aapsLogger.info(LTag.PUMP, "setExtendedBolus - insulin: $insulin, durationInMinutes: $durationInMinutes")
- return PumpEnactResult(injector).success(false).enacted(false)
- .comment("Medtrum driver does not support extended boluses")
+ return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum driver does not support extended boluses")
}
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
@@ -255,15 +252,15 @@ class MedtrumPlugin @Inject constructor(
}
override fun model(): PumpType {
- return mPumpType
+ return medtrumPump.pumpType
}
override fun serialNumber(): String {
- return "0" // TODO
+ return medtrumPump.pumpSN.toString(radix = 16)
}
override val pumpDescription: PumpDescription
- get() = mPumpDescription
+ get() = PumpDescription(medtrumPump.pumpType)
override fun shortStatus(veryShort: Boolean): String {
return ""// TODO
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 0536be865c..6791190162 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -1,13 +1,9 @@
package info.nightscout.pump.medtrum
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.profile.Profile
-import info.nightscout.interfaces.profile.ProfileStore
-import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.defs.PumpType
+import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
@@ -15,7 +11,6 @@ import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
-import info.nightscout.shared.utils.T
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
@@ -26,31 +21,44 @@ import kotlin.math.round
class MedtrumPump @Inject constructor(
private val aapsLogger: AAPSLogger,
private val sp: SP,
- private val dateUtil: DateUtil,
- private val instantiator: Instantiator
+ private val dateUtil: DateUtil
) {
+ // Connection state flow
+ private val _connectionState = MutableStateFlow(ConnectionState.DISCONNECTED)
+ val connectionStateFlow: StateFlow = _connectionState
+ var connectionState: ConnectionState
+ get() = _connectionState.value
+ set(value) {
+ _connectionState.value = value
+ }
+
// Pump state flow
- // TODO We might want to save this in SP, or at least get activated state from SP
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
val pumpStateFlow: StateFlow = _pumpState
-
var pumpState: MedtrumPumpState
get() = _pumpState.value
set(value) {
_pumpState.value = value
}
+ var _patchActivated = false
+ val patchActivated: Boolean
+ get() = _patchActivated
+
// Prime progress as state flow
private val _primeProgress = MutableStateFlow(0)
val primeProgressFlow: StateFlow = _primeProgress
-
var primeProgress: Int
get() = _primeProgress.value
set(value) {
_primeProgress.value = value
}
+ var pumpSN = 0L
+ val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection
+ var patchSessionToken = 0L
+
// TODO: Save this in SP? This might be a bit tricky as we only know what we have set, not what the pump has set but the pump should not change it, addtionally we should track the active basal profile in pump e.g. Basal patern A, B etc
var actualBasalProfile = byteArrayOf(0)
var patchId = 0L
@@ -86,6 +94,19 @@ class MedtrumPump @Inject constructor(
var desiredHourlyMaxInsulin: Int = 40
var desiredDailyMaxInsulin: Int = 180
+ fun setPatchActivatedState(activated: Boolean) {
+ aapsLogger.debug(LTag.PUMP, "setPatchActivatedState: $activated")
+ _patchActivated = activated
+ sp.putBoolean(R.string.key_patch_activated, activated)
+ }
+
+ /** When the activation/deactivation screen, and the connection flow needs to be controlled,
+ * this can be used to set the ActivatedState without saving to SP, So when app is force closed the state is still maintained */
+ fun setPatchActivatedStateTemp(activated: Boolean) {
+ aapsLogger.debug(LTag.PUMP, "setPatchActivatedStateTemp: $activated")
+ _patchActivated = activated
+ }
+
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
val list = nsProfile.getBasalValues()
var basals = byteArrayOf()
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/ConnectionState.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/ConnectionState.kt
new file mode 100644
index 0000000000..1b64d5f326
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/ConnectionState.kt
@@ -0,0 +1,7 @@
+package info.nightscout.pump.medtrum.code
+
+enum class ConnectionState {
+ CONNECTED,
+ DISCONNECTED,
+ CONNECTING;
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
index 8d615dd713..c3e7bc9ab5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
@@ -1,11 +1,9 @@
package info.nightscout.pump.medtrum.code
enum class PatchStep {
- SAFE_DEACTIVATION,
- MANUALLY_TURNING_OFF_ALARM,
- DISCARDED,
- DISCARDED_FOR_CHANGE,
- DISCARDED_FROM_ALARM,
+ START_DEACTIVATION,
+ DEACTIVATE,
+ DEACTIVATION_COMPLETE,
PREPARE_PATCH,
PRIME,
ATTACH_PATCH,
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
index 4e70df0638..6b5c00d117 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
@@ -1,6 +1,8 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
+import info.nightscout.interfaces.pump.DetailedBolusInfo
+import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.ACTIVATE
import info.nightscout.pump.medtrum.extension.toByteArray
@@ -16,6 +18,7 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
@Inject lateinit var medtrumPump: MedtrumPump
@Inject lateinit var tddCalculator: TddCalculator
+ @Inject lateinit var pumpSync: PumpSync
companion object {
@@ -95,6 +98,22 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
medtrumPump.actualBasalProfile = basalProfile
// TODO: Handle history entry
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
+
+ // Update the pump in the database, technically this is not a new pump only new patch, but still TBR's etc need to be cannceled
+ pumpSync.connectNewPump()
+ // Sync canula change
+ pumpSync.insertTherapyEventIfNewWithTimestamp(
+ timestamp = System.currentTimeMillis(),
+ type = DetailedBolusInfo.EventType.CANNULA_CHANGE,
+ pumpType = medtrumPump.pumpType,
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ pumpSync.insertTherapyEventIfNewWithTimestamp(
+ timestamp = System.currentTimeMillis(),
+ type = DetailedBolusInfo.EventType.INSULIN_CHANGE,
+ pumpType = medtrumPump.pumpType,
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
}
return success
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
index f8c6a28729..4cf10a580c 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
@@ -1,12 +1,16 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.AUTH_REQ
import info.nightscout.pump.medtrum.encryption.Crypt
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
+import javax.inject.Inject
-class AuthorizePacket(injector: HasAndroidInjector, private val deviceSerial: Long) : MedtrumPacket(injector) {
+class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ @Inject lateinit var medtrumPump: MedtrumPump
var deviceType: Int = 0
var swVersion: String = ""
@@ -30,8 +34,8 @@ class AuthorizePacket(injector: HasAndroidInjector, private val deviceSerial: Lo
override fun getRequest(): ByteArray {
val role = 2 // Fixed to 2 for pump
- val key = Crypt().keyGen(deviceSerial)
- return byteArrayOf(opCode) + byteArrayOf(role.toByte()) + 0.toByteArray(4) + key.toByteArray(4)
+ val key = Crypt().keyGen(medtrumPump.pumpSN)
+ return byteArrayOf(opCode) + byteArrayOf(role.toByte()) + medtrumPump.patchSessionToken.toByteArray(4) + key.toByteArray(4)
}
override fun handleResponse(data: ByteArray): Boolean {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index 88f9f2bf70..3898488ea4 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -115,15 +115,19 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_BASAL != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Basal notification received")
- var basalType = data.copyOfRange(offset, offset + 1)
- var basalSequence = data.copyOfRange(offset + 1, offset + 3)
- var basalInterval = data.copyOfRange(offset + 3, offset + 7)
- var basalRateAndDelivery = data.copyOfRange(offset + 7, offset + 10).toInt()
- var basalRate = basalRateAndDelivery and 0xFFF
- var basalDelivery = (basalRateAndDelivery shr 12)
- aapsLogger.debug(LTag.PUMPCOMM, "Basal type: $basalType, basal sequence: $basalSequence, basal interval: $basalInterval, basal rate: $basalRate, basal delivery: $basalDelivery")
+ var basalType = data.copyOfRange(offset, offset + 1).toInt()
+ var basalSequence = data.copyOfRange(offset + 1, offset + 3).toInt()
+ var basalPatchId = data.copyOfRange(offset + 3, offset + 5).toInt()
+ var basalInterval = data.copyOfRange(offset + 5, offset + 9).toInt()
+ var basalRateAndDelivery = data.copyOfRange(offset + 9, offset + 12).toInt()
+ var basalRate = (basalRateAndDelivery and 0xFFF) * 0.05
+ var basalDelivery = (basalRateAndDelivery shr 12) * 0.05
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal interval: $basalInterval, basal rate: $basalRate, basal delivery: $basalDelivery"
+ )
// TODO Sync basal flow
- offset += 10
+ offset += 12
}
if (fieldMask and MASK_SETUP != 0) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
index 3d3b8919cd..25603ab982 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
@@ -10,6 +10,7 @@ class SetBolusMotorPacket(injector: HasAndroidInjector) : MedtrumPacket(injector
}
override fun getRequest(): ByteArray {
+ // TODO CHECK! Seems to be a feature? to set the bolus to vibrate? TEST!
return byteArrayOf(opCode) + 0.toByte()
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
index 71b022e848..5f649e22cd 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
@@ -6,6 +6,7 @@ import info.nightscout.pump.medtrum.comm.enums.CommandType.SYNCHRONIZE
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import javax.inject.Inject
@@ -37,6 +38,7 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
var state = MedtrumPumpState.fromByte(data[RESP_STATE_START])
medtrumPump.pumpState = state
+ aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: state: $state")
var fieldMask = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
var syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
index 9b5548b746..429cf3f319 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
@@ -9,8 +9,10 @@ import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoMap
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumActivateFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumDeactivatePatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumStartDeactivationFragment
import info.nightscout.pump.medtrum.services.MedtrumService
import info.nightscout.pump.medtrum.ui.MedtrumActivity
import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
@@ -50,6 +52,14 @@ abstract class MedtrumModule {
@ContributesAndroidInjector
abstract fun contributesMedtrumOverviewFragment(): MedtrumOverviewFragment
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesStartDeactivationFragment(): MedtrumStartDeactivationFragment
+
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesDeactivatePatchFragment(): MedtrumDeactivatePatchFragment
+
@FragmentScope
@ContributesAndroidInjector
internal abstract fun contributesPreparePatchFragment(): MedtrumPreparePatchFragment
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
index 4cd3e182bc..ce5126de48 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/encryption/Crypt.kt
@@ -4,6 +4,7 @@ import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toLong
class Crypt {
+
private val RIJNDEAL_S_BOX: IntArray = intArrayOf(99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22)
private val RIJNDEAL_INVERSE_S_BOX: IntArray = intArrayOf(82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125)
@@ -14,16 +15,11 @@ class Crypt {
return simpleCrypt(key)
}
- fun randomGen(input: Long): Long {
- val A = 16807
- val Q = 127773
- val R = 2836
- val tmp1 = input / Q
- var ret = (input - (tmp1 * Q)) * A - (tmp1 * R)
- if (ret < 0) {
- ret += 2147483647L
- }
- return ret
+ fun generateRandomToken(): Long {
+ val randomBytes = ByteArray(4)
+ val random = java.security.SecureRandom()
+ random.nextBytes(randomBytes)
+ return randomBytes.toLong()
}
private fun simpleCrypt(inputData: Long): Long {
@@ -42,6 +38,18 @@ class Crypt {
return temp xor MED_CIPHER
}
+ private fun randomGen(input: Long): Long {
+ val A = 16807
+ val Q = 127773
+ val R = 2836
+ val tmp1 = input / Q
+ var ret = (input - (tmp1 * Q)) * A - (tmp1 * R)
+ if (ret < 0) {
+ ret += 2147483647L
+ }
+ return ret
+ }
+
private fun changeByTable(inputData: Long, tableData: IntArray): Long {
val value = inputData.toByteArray(4)
val results = ByteArray(4)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 68fe0fd3a8..71c566ee38 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -18,6 +18,8 @@ import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.medtrum.MedtrumPlugin
import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.comm.packets.*
import info.nightscout.pump.medtrum.extension.toInt
@@ -67,14 +69,13 @@ class MedtrumService : DaggerService(), BLECommCallback {
private val disposable = CompositeDisposable()
private val mBinder: IBinder = LocalBinder()
- private var mDeviceSN: Long = 0
private var currentState: State = IdleState()
private var mPacket: MedtrumPacket? = null
- var isConnected = false
- var isConnecting = false
-
- // TODO: Stuff like this in a settings class?
- private var mLastDeviceTime: Long = 0
+
+ val isConnected: Boolean
+ get() = medtrumPump.connectionState == ConnectionState.CONNECTED
+ val isConnecting: Boolean
+ get() = medtrumPump.connectionState == ConnectionState.CONNECTING
override fun onCreate() {
super.onCreate()
@@ -88,11 +89,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
.observeOn(aapsSchedulers.io)
.subscribe({ event ->
if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput))) {
- pumpSync.connectNewPump()
changePump()
}
}, fabricPrivacy::logException)
changePump()
+ // TODO: We should probably listen to the pump state as well and handle some state changes? Or do we handle that in the packets or medtrumPump?
}
override fun onDestroy() {
@@ -101,12 +102,13 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun connect(from: String): Boolean {
- aapsLogger.debug(LTag.PUMP, "connect: called!")
+ aapsLogger.debug(LTag.PUMP, "connect: called from: $from")
if (currentState is IdleState) {
- isConnecting = true
- isConnected = false
- rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING))
- return bleComm.connect(from, mDeviceSN)
+ medtrumPump.connectionState = ConnectionState.CONNECTING
+ if (medtrumPump.patchActivated) {
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING))
+ }
+ return bleComm.connect(from, medtrumPump.pumpSN)
} else {
aapsLogger.error(LTag.PUMPCOMM, "Connect attempt when in non Idle state from: $from")
return false
@@ -119,12 +121,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun startActivate(): Boolean {
- // TODO not sure this is the correct way lol, We might need to tell AAPS which profile is active
val profile = profileFunction.getProfile()?.let { medtrumPump.buildMedtrumProfileArray(it) }
val packet = profile?.let { ActivatePacket(injector, it) }
return packet?.let { sendPacketAndGetResponse(it) } == true
}
+ fun deactivatePatch(): Boolean {
+ return sendPacketAndGetResponse(StopPatchPacket(injector))
+ }
+
fun stopConnecting() {
// TODO proper way for this might need send commands etc
bleComm.stopConnecting()
@@ -136,7 +141,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun readPumpStatus() {
- // TODO
+ // TODO read pump history
}
fun loadEvents(): PumpEnactResult {
@@ -150,12 +155,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
return result
}
- fun setUserSettings(): PumpEnactResult {
- // TODO need this? Check
- val result = PumpEnactResult(injector)
- return result
- }
-
fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean {
if (!isConnected) return false
// TODO
@@ -174,15 +173,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun changePump() {
aapsLogger.debug(LTag.PUMP, "changePump: called!")
try {
- mDeviceSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
+ medtrumPump.pumpSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
} catch (e: NumberFormatException) {
aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
}
- // TODO: What do we do with active patch here? Getting status should be enough?
- when (currentState) {
- is IdleState -> connect("changePump")
- // is ReadyState -> disconnect("changePump")
- else -> null // TODO: What to do here? Abort stuff?
+ medtrumPump.setPatchActivatedState(sp.getBoolean(R.string.key_patch_activated, false))
+ medtrumPump.patchSessionToken = sp.getLong(R.string.key_session_token, 0)
+ if (medtrumPump.patchActivated) {
+ aapsLogger.debug(LTag.PUMP, "changePump: Patch is already activated, setting as ACTIVE")
+ medtrumPump.pumpState = MedtrumPumpState.ACTIVE // Set inital status as active will be updated on first connection
}
}
@@ -260,10 +259,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
open fun onDisconnected() {
aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected")
- isConnecting = false
- isConnected = false
- rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
-
+ medtrumPump.connectionState = ConnectionState.DISCONNECTED
+ if (medtrumPump.patchActivated) {
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
+ }
// TODO: Check flow for this
toState(IdleState())
}
@@ -277,7 +276,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached IdleState")
- connect("IdleState onEnter")
}
override fun onConnected() {
@@ -287,7 +285,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onDisconnected() {
super.onDisconnected()
- connect("IdleState onDisconnected")
}
}
@@ -296,7 +293,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached AuthState")
- mPacket = AuthorizePacket(injector, mDeviceSN)
+ mPacket = AuthorizePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
}
@@ -427,7 +424,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
- // TODO: Handle pump state parameters
toState(SubscribeState())
} else if (mPacket?.failed == true) {
// Failure
@@ -464,9 +460,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!")
// Now we are fully connected and authenticated and we can start sending commands. Let AAPS know
- isConnecting = false
- isConnected = true
- rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
+ medtrumPump.connectionState = ConnectionState.CONNECTED
+ if (medtrumPump.patchActivated) {
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
+ }
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
index 1c0edd9f94..77656cefb5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
@@ -11,8 +11,10 @@ import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.ViewModelProvider
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumActivateFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumDeactivatePatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
+import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumStartDeactivationFragment
import info.nightscout.core.utils.extensions.safeGetSerializableExtra
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.PatchStep
@@ -42,13 +44,16 @@ class MedtrumActivity : MedtrumBaseActivity() {
patchStep.observe(this@MedtrumActivity) {
when (it) {
- PatchStep.PREPARE_PATCH -> setupViewFragment(MedtrumPreparePatchFragment.newInstance())
- PatchStep.PRIME -> setupViewFragment(MedtrumPrimeFragment.newInstance())
- PatchStep.ATTACH_PATCH -> setupViewFragment(MedtrumAttachPatchFragment.newInstance())
- PatchStep.ACTIVATE -> setupViewFragment(MedtrumActivateFragment.newInstance())
- PatchStep.COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
- PatchStep.CANCEL -> this@MedtrumActivity.finish()
- else -> Unit
+ PatchStep.PREPARE_PATCH -> setupViewFragment(MedtrumPreparePatchFragment.newInstance())
+ PatchStep.PRIME -> setupViewFragment(MedtrumPrimeFragment.newInstance())
+ PatchStep.ATTACH_PATCH -> setupViewFragment(MedtrumAttachPatchFragment.newInstance())
+ PatchStep.ACTIVATE -> setupViewFragment(MedtrumActivateFragment.newInstance())
+ PatchStep.COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
+ PatchStep.CANCEL -> this@MedtrumActivity.finish()
+ PatchStep.START_DEACTIVATION -> setupViewFragment(MedtrumStartDeactivationFragment.newInstance())
+ PatchStep.DEACTIVATE -> setupViewFragment(MedtrumDeactivatePatchFragment.newInstance())
+ PatchStep.DEACTIVATION_COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
+ else -> Unit
}
}
}
@@ -85,8 +90,7 @@ class MedtrumActivity : MedtrumBaseActivity() {
const val EXTRA_START_PATCH_STEP = "EXTRA_START_PATCH_FRAGMENT_UI"
const val EXTRA_START_FROM_MENU = "EXTRA_START_FROM_MENU"
- @JvmStatic
- fun createIntentFromMenu(context: Context, patchStep: PatchStep): Intent {
+ @JvmStatic fun createIntentFromMenu(context: Context, patchStep: PatchStep): Intent {
return Intent(context, MedtrumActivity::class.java).apply {
putExtra(EXTRA_START_PATCH_STEP, patchStep)
putExtra(EXTRA_START_FROM_MENU, true)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivatePatchFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivatePatchFragment.kt
new file mode 100644
index 0000000000..0791f8cb79
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivatePatchFragment.kt
@@ -0,0 +1,49 @@
+package info.nightscout.androidaps.plugins.pump.eopatch.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumDeactivatePatchBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumDeactivatePatchFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumDeactivatePatchFragment = MedtrumDeactivatePatchFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_deactivate_patch
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ aapsLogger.debug(LTag.PUMP, "MedtrumDeactivatePatchFragment onViewCreated")
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.STOPPED -> btnPositive.visibility = View.VISIBLE
+
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error deactivate") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+
+ else -> Unit // Nothing to do here
+ }
+ }
+ deactivatePatch()
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index 3ee8141993..66c66249e0 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -43,13 +43,19 @@ class MedtrumOverviewFragment : MedtrumBaseFragment
when (evt.peekContent()) {
- EventType.ACTIVATION_CLICKED -> requireContext().apply {
+ EventType.ACTIVATION_CLICKED -> requireContext().apply {
val step = convertToPatchStep(medtrumPump.pumpState)
+ // TODO is stil needed?
if (step != PatchStep.PREPARE_PATCH) {
aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step")
}
- startActivity(MedtrumActivity.createIntentFromMenu(this, step)) }
- else -> Unit
+ startActivity(MedtrumActivity.createIntentFromMenu(this, step))
+ }
+
+ EventType.DEACTIVATION_CLICKED -> requireContext().apply {
+ startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.START_DEACTIVATION))
+ }
+ else -> Unit
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumStartDeactivationFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumStartDeactivationFragment.kt
new file mode 100644
index 0000000000..7e9814c667
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumStartDeactivationFragment.kt
@@ -0,0 +1,49 @@
+package info.nightscout.androidaps.plugins.pump.eopatch.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumStartDeactivationBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumStartDeactivationFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumStartDeactivationFragment = MedtrumStartDeactivationFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_start_deactivation
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ aapsLogger.debug(LTag.PUMP, "MedtrumStartDeactivationFragment onViewCreated")
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.READY_DEACTIVATE -> btnPositive.visibility = View.VISIBLE
+
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error deactivate") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+
+ else -> Unit // Nothing to do here
+ }
+ }
+ startDeactivation()
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index 2aaddfb663..e1f1c74ecb 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -10,6 +10,7 @@ import info.nightscout.pump.medtrum.ui.event.UIEvent
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
@@ -20,6 +21,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -32,7 +34,6 @@ class MedtrumOverviewViewModel @Inject constructor(
private val medtrumPump: MedtrumPump
) : BaseViewModel() {
- private var disposable: CompositeDisposable = CompositeDisposable()
private val scope = CoroutineScope(Dispatchers.Default)
private val _eventHandler = SingleLiveEvent>()
@@ -48,29 +49,28 @@ class MedtrumOverviewViewModel @Inject constructor(
get() = _isPatchActivated
init {
- // TODO proper connection state from medtrumPump
- disposable += rxBus
- .toObservable(EventPumpStatusChanged::class.java)
- .observeOn(aapsSchedulers.main)
- .subscribe({
- _bleStatus.value = when (it.status) {
- EventPumpStatusChanged.Status.CONNECTING ->
- "{fa-bluetooth-b spin} ${it.secondsElapsed}s"
+ scope.launch {
+ medtrumPump.connectionStateFlow.collect { state ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel connectionStateFlow: $state")
+ when (state) {
+ ConnectionState.CONNECTING -> {
+ _bleStatus.postValue("{fa-bluetooth-b spin}")
+ }
- EventPumpStatusChanged.Status.CONNECTED ->
- "{fa-bluetooth}"
+ ConnectionState.CONNECTED -> {
+ _bleStatus.postValue("{fa-bluetooth}")
+ }
- EventPumpStatusChanged.Status.DISCONNECTED ->
- "{fa-bluetooth-b}"
-
- else ->
- ""
- }
- }, fabricPrivacy::logException)
+ ConnectionState.DISCONNECTED -> {
+ _bleStatus.postValue("{fa-bluetooth-b}")
+ }
+ }
+ }
+ }
scope.launch {
medtrumPump.pumpStateFlow.collect { state ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
- if (state > MedtrumPumpState.EJECTED) {
+ if (state > MedtrumPumpState.EJECTED && state < MedtrumPumpState.STOPPED) {
_isPatchActivated.postValue(true)
} else {
_isPatchActivated.postValue(false)
@@ -79,6 +79,11 @@ class MedtrumOverviewViewModel @Inject constructor(
}
}
+ override fun onCleared() {
+ super.onCleared()
+ scope.cancel()
+ }
+
fun onClickActivation() {
aapsLogger.debug(LTag.PUMP, "Start Patch clicked!")
val profile = profileFunction.getProfile()
@@ -91,6 +96,6 @@ class MedtrumOverviewViewModel @Inject constructor(
fun onClickDeactivation() {
aapsLogger.debug(LTag.PUMP, "Stop Patch clicked!")
- // TODO
+ _eventHandler.postValue(UIEvent(EventType.DEACTIVATION_CLICKED))
}
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
index 1be28aa66a..2b2650427b 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
@@ -6,10 +6,12 @@ import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.pump.medtrum.MedtrumPlugin
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.services.MedtrumService
import info.nightscout.pump.medtrum.code.EventType
import info.nightscout.pump.medtrum.code.PatchStep
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
+import info.nightscout.pump.medtrum.encryption.Crypt
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
import info.nightscout.pump.medtrum.ui.event.UIEvent
@@ -22,6 +24,7 @@ import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -54,37 +57,74 @@ class MedtrumViewModel @Inject constructor(
private var mInitPatchStep: PatchStep? = null
init {
+ // TODO destroy scope
scope.launch {
- medtrumPump.pumpStateFlow.collect { state ->
- aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
- when (state) {
- MedtrumPumpState.NONE, MedtrumPumpState.IDLE -> {
- setupStep.postValue(SetupStep.INITIAL)
- }
+ medtrumPump.connectionStateFlow.collect { state ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel connectionStateFlow: $state")
+ if (patchStep.value != null) {
+ when (state) {
+ ConnectionState.CONNECTED -> {
+ if (patchStep.value == PatchStep.START_DEACTIVATION) {
+ updateSetupStep(SetupStep.READY_DEACTIVATE)
+ }
+ }
- MedtrumPumpState.FILLED -> {
- setupStep.postValue(SetupStep.FILLED)
- }
+ ConnectionState.DISCONNECTED -> {
+ if (patchStep.value != PatchStep.DEACTIVATION_COMPLETE && patchStep.value != PatchStep.COMPLETE && patchStep.value != PatchStep.CANCEL) {
+ medtrumService?.connect("Try reconnect from viewModel")
+ }
+ }
- MedtrumPumpState.PRIMING -> {
- // setupStep.postValue(SetupStep.PRIMING)
- // TODO: What to do here? start prime counter?
- }
-
- MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> {
- setupStep.postValue(SetupStep.PRIMED)
- }
-
- MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
- setupStep.postValue(SetupStep.ACTIVATED)
- }
-
- else -> {
- setupStep.postValue(SetupStep.ERROR)
+ ConnectionState.CONNECTING -> {
+ }
}
}
}
}
+ scope.launch {
+ medtrumPump.pumpStateFlow.collect { state ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
+ if (patchStep.value != null) {
+ when (state) {
+ MedtrumPumpState.NONE, MedtrumPumpState.IDLE -> {
+ updateSetupStep(SetupStep.INITIAL)
+ }
+
+ MedtrumPumpState.FILLED -> {
+ updateSetupStep(SetupStep.FILLED)
+ }
+
+ MedtrumPumpState.PRIMING -> {
+ // updateSetupStep(SetupStep.PRIMING)
+ // TODO: What to do here? start prime counter?
+ }
+
+ MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> {
+ updateSetupStep(SetupStep.PRIMED)
+ }
+
+ MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
+ medtrumPump.setPatchActivatedState(true)
+ updateSetupStep(SetupStep.ACTIVATED)
+ }
+
+ MedtrumPumpState.STOPPED -> {
+ medtrumPump.setPatchActivatedState(false)
+ updateSetupStep(SetupStep.STOPPED)
+ }
+
+ else -> {
+ updateSetupStep(SetupStep.ERROR)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun onCleared() {
+ super.onCleared()
+ scope.cancel()
}
fun moveStep(newPatchStep: PatchStep) {
@@ -92,14 +132,27 @@ class MedtrumViewModel @Inject constructor(
if (oldPatchStep != newPatchStep) {
when (newPatchStep) {
- PatchStep.CANCEL -> {
- // if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Cancel") else {
- // }
+ PatchStep.CANCEL -> {
+ if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Cancel") else {
+ }
+ // TODO: For DEACTIVATE STATE we might want to move to force cancel screen
+ if (oldPatchStep == PatchStep.START_DEACTIVATION || oldPatchStep == PatchStep.DEACTIVATE) {
+ // Deactivation was canceled
+ medtrumPump.setPatchActivatedStateTemp(true)
+ }
}
- else -> null
- }?.let {
- // TODO Update lifecycle
+ PatchStep.COMPLETE -> {
+ if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("Complete") else {
+ }
+ }
+
+ PatchStep.DEACTIVATION_COMPLETE -> {
+ if (medtrumService?.isConnected == true || medtrumService?.isConnecting == true) medtrumService?.disconnect("DeactivationComplete") else {
+ }
+ }
+
+ else -> {}
}
}
@@ -113,12 +166,20 @@ class MedtrumViewModel @Inject constructor(
}
fun preparePatch() {
- // TODO When we dont need to connect what needs to be done here?
+ if (medtrumPump.patchActivated == true) {
+ aapsLogger.warn(LTag.PUMP, "preparePatch: already activated! conflicting state?")
+ // In this case user could have removed the patch without deactivating it?
+ medtrumPump.setPatchActivatedState(false)
+ }
+ // New session, generate new session token
+ aapsLogger.info(LTag.PUMP, "preparePatch: new session")
+ medtrumPump.patchSessionToken = Crypt().generateRandomToken()
+ sp.putLong(R.string.key_session_token, medtrumPump.patchSessionToken)
+ // Connect to pump
medtrumService?.connect("PreparePatch")
}
fun startPrime() {
- // TODO: Get result from service
if (medtrumPump.pumpState == MedtrumPumpState.PRIMING) {
aapsLogger.info(LTag.PUMP, "startPrime: already priming!")
} else {
@@ -126,7 +187,7 @@ class MedtrumViewModel @Inject constructor(
aapsLogger.info(LTag.PUMP, "startPrime: success!")
} else {
aapsLogger.info(LTag.PUMP, "startPrime: failure!")
- setupStep.postValue(SetupStep.ERROR)
+ updateSetupStep(SetupStep.ERROR)
}
}
}
@@ -136,20 +197,46 @@ class MedtrumViewModel @Inject constructor(
aapsLogger.info(LTag.PUMP, "startActivate: success!")
} else {
aapsLogger.info(LTag.PUMP, "startActivate: failure!")
- setupStep.postValue(SetupStep.ERROR)
+ updateSetupStep(SetupStep.ERROR)
+ }
+ }
+
+ fun startDeactivation() {
+ // Set active already to false, so UI can control the pump connection instead of AAPS pumpqueue
+ medtrumPump.setPatchActivatedStateTemp(false)
+
+ // Start connecting if needed
+ if (medtrumService?.isConnected == true) {
+ updateSetupStep(SetupStep.READY_DEACTIVATE)
+ } else if (medtrumService?.isConnecting != true) {
+ medtrumService?.connect("StartDeactivation")
+ }
+ // TODO: Also start timer to check if connection is made, if timed out show force forget patch
+ }
+
+ fun deactivatePatch() {
+ if (medtrumService?.deactivatePatch() == true) {
+ aapsLogger.info(LTag.PUMP, "deactivatePatch: success!")
+ } else {
+ aapsLogger.info(LTag.PUMP, "deactivatePatch: failure!")
+ // Check if this is needed, for now even when it failed, we assume the user will remove the patch and pumpbase
+ medtrumPump.setPatchActivatedStateTemp(true) // failed to activate, set activate state to true
+ // TODO: State to force forget the patch or try again
+ updateSetupStep(SetupStep.ERROR)
}
}
private fun prepareStep(step: PatchStep?): PatchStep {
- // TODO Title per screen :) And proper sync with patchstate
(step ?: convertToPatchStep(medtrumPump.pumpState)).let { newStep ->
when (newStep) {
- PatchStep.PREPARE_PATCH -> R.string.step_prepare_patch
- PatchStep.PRIME -> R.string.step_prime
- PatchStep.ATTACH_PATCH -> R.string.step_attach
- PatchStep.ACTIVATE -> R.string.step_activate
- PatchStep.COMPLETE -> R.string.step_complete
- else -> _title.value
+ PatchStep.PREPARE_PATCH -> R.string.step_prepare_patch
+ PatchStep.PRIME -> R.string.step_prime
+ PatchStep.ATTACH_PATCH -> R.string.step_attach
+ PatchStep.ACTIVATE -> R.string.step_activate
+ PatchStep.COMPLETE -> R.string.step_complete
+ PatchStep.START_DEACTIVATION, PatchStep.DEACTIVATE -> R.string.step_deactivate
+ PatchStep.DEACTIVATION_COMPLETE -> R.string.step_complete
+ else -> _title.value
}.let {
aapsLogger.info(LTag.PUMP, "prepareStep: title before cond: $it")
if (_title.value != it) {
@@ -164,12 +251,7 @@ class MedtrumViewModel @Inject constructor(
}
}
- enum class SetupStep {
- INITIAL,
- FILLED,
- PRIMED,
- ACTIVATED,
- ERROR
+ enum class SetupStep { INITIAL, FILLED, PRIMED, ACTIVATED, ERROR, START_DEACTIVATION, STOPPED, READY_DEACTIVATE
}
val setupStep = MutableLiveData()
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_deactivate_patch.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_deactivate_patch.xml
new file mode 100644
index 0000000000..7499000c0f
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_deactivate_patch.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_start_deactivation.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_start_deactivation.xml
new file mode 100644
index 0000000000..a92acd6e10
--- /dev/null
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_start_deactivation.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index fc0f73358a..b9081caef4 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -3,6 +3,8 @@
snInput
medtrumpump_settings
+ medtrum_patch_activated
+ medtrum_session_token
Medtrum
MEDTRUM
@@ -20,12 +22,14 @@
Start priming
Start activation
Complete
+ Deactivate patch
Prepare patch
Priming
Attach patch
Activation
Complete
+ Deactivation
SN
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
index a1ef7c20c8..b7494eb858 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
@@ -3,6 +3,7 @@ package info.nightscout.pump.medtrum
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.interfaces.profile.Instantiator
+import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.stats.TddCalculator
import org.junit.jupiter.api.BeforeEach
import org.mockito.Mock
@@ -12,11 +13,12 @@ open class MedtrumTestBase: TestBaseWithProfile() {
@Mock lateinit var sp: SP
@Mock lateinit var instantiator: Instantiator
@Mock lateinit var tddCalculator: TddCalculator
+ @Mock lateinit var pumpSync: PumpSync
lateinit var medtrumPump: MedtrumPump
@BeforeEach
fun setup() {
- medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil, instantiator)
+ medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil)
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
index 13f41b0fbc..609e47ca87 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
@@ -17,6 +17,7 @@ class ActivatePacketTest : MedtrumTestBase() {
it.aapsLogger = aapsLogger
it.medtrumPump = medtrumPump
it.tddCalculator = tddCalculator
+ it.pumpSync = pumpSync
}
}
}
@@ -35,7 +36,7 @@ class ActivatePacketTest : MedtrumTestBase() {
val result = packet.getRequest()
// Expected values
- val expectedByteArray = byteArrayOf(18, 0, 0, 1, 6, 0, 0, 0, 32, 3, 16, 14, 0, 0, 1, 3, 16, 14, 0, 0, 1, 2, 12, 12, 12)
+ val expectedByteArray = byteArrayOf(18, 0, 12, 1, 6, 0, 0, 30, 32, 3, 16, 14, 0, 0, 1, 3, 16, 14, 0, 0, 1, 2, 12, 12, 12)
assertEquals(expectedByteArray.contentToString(), result.contentToString())
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
index 01b9248288..c72fcb4ecb 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
@@ -13,8 +13,9 @@ class AuthorizePacketTest : MedtrumTestBase() {
private val packetInjector = HasAndroidInjector {
AndroidInjector {
- if (it is MedtrumPacket) {
+ if (it is AuthorizePacket) {
it.aapsLogger = aapsLogger
+ it.medtrumPump = medtrumPump
}
}
}
@@ -22,16 +23,17 @@ class AuthorizePacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketAndSNWhenCalledThenReturnAuthorizePacket() {
// Inputs
val opCode = 5
- val sn = 2859923929
+ medtrumPump.pumpSN = 2859923929
+ medtrumPump.patchSessionToken = 667
// Call
- val packet = AuthorizePacket(packetInjector, sn)
+ val packet = AuthorizePacket(packetInjector)
val result = packet.getRequest()
// Expected values
val key = 3364239851
val type = 2
- val expectedByteArray = byteArrayOf(opCode.toByte()) + type.toByte() + 0.toByteArray(4) + key.toByteArray(4)
+ val expectedByteArray = byteArrayOf(opCode.toByte()) + type.toByte() + medtrumPump.patchSessionToken.toByteArray(4) + key.toByteArray(4)
assertEquals(10, result.size)
assertEquals(expectedByteArray.contentToString(), result.contentToString())
}
@@ -47,7 +49,7 @@ class AuthorizePacketTest : MedtrumTestBase() {
// Call
val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2) + 0.toByte() + deviceType.toByte() + swVerX.toByte() + swVerY.toByte() + swVerZ.toByte()
- val packet = AuthorizePacket(packetInjector, 0)
+ val packet = AuthorizePacket(packetInjector)
val result = packet.handleResponse(response)
// Expected values
@@ -65,7 +67,7 @@ class AuthorizePacketTest : MedtrumTestBase() {
// Call
val response = byteArrayOf(0) + opCode.toByte() + 0.toByteArray(2) + responseCode.toByteArray(2)
- val packet = AuthorizePacket(packetInjector, 0)
+ val packet = AuthorizePacket(packetInjector)
packet.opCode = opCode.toByte()
val result = packet.handleResponse(response)
From 0d8f07ad0abd6380c5c4e520320f15f8e0aa04ec Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 20 May 2023 20:40:55 +0200
Subject: [PATCH 018/116] Initial TBR implementation and pumpSync for basals
etc
---
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 43 +++-
.../nightscout/pump/medtrum/MedtrumPump.kt | 241 ++++++++++++++++--
.../pump/medtrum/comm/enums/BasalType.kt | 58 +++++
.../medtrum/comm/packets/ActivatePacket.kt | 11 +-
.../comm/packets/CancelTempBasalPacket.kt | 8 +-
.../medtrum/comm/packets/GetRecordPacket.kt | 163 +++++++++++-
.../medtrum/comm/packets/GetTimePacket.kt | 2 +-
.../comm/packets/NotificationPacket.kt | 30 ++-
.../comm/packets/SetBasalProfilePacket.kt | 7 +-
.../comm/packets/SetTempBasalPacket.kt | 16 +-
.../medtrum/comm/packets/StopPatchPacket.kt | 3 +-
.../pump/medtrum/services/MedtrumService.kt | 101 ++++++--
.../medtrum/ui/MedtrumOverviewFragment.kt | 6 +-
.../medtrum/ui/viewmodel/MedtrumViewModel.kt | 3 +-
.../pump/medtrum/util/MedtrumTimeUtil.kt | 10 +-
pump/medtrum/src/main/res/values/strings.xml | 13 +-
.../pump/medtrum/MedtrumTestBase.kt | 4 +-
.../comm/packets/AuthorizePacketTest.kt | 5 +-
.../medtrum/comm/packets/GetTimePacketTest.kt | 2 +-
19 files changed, 622 insertions(+), 104 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BasalType.kt
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 9ab782dd7d..0d2870fe36 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -18,6 +18,7 @@ import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.pump.PumpPluginBase
import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.pump.TemporaryBasalStorage
import info.nightscout.interfaces.pump.actions.CustomAction
import info.nightscout.interfaces.pump.actions.CustomActionType
import info.nightscout.interfaces.pump.defs.ManufacturerType
@@ -51,6 +52,7 @@ import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
+import kotlin.math.round
@Singleton class MedtrumPlugin @Inject constructor(
injector: HasAndroidInjector,
@@ -63,10 +65,11 @@ import javax.inject.Singleton
private val context: Context,
private val fabricPrivacy: FabricPrivacy,
private val dateUtil: DateUtil,
- private val pumpSync: PumpSync,
private val medtrumPump: MedtrumPump,
private val uiInteraction: UiInteraction,
- private val profileFunction: ProfileFunction
+ private val profileFunction: ProfileFunction,
+ private val pumpSync: PumpSync,
+ private val temporaryBasalStorage: TemporaryBasalStorage
) : PumpPluginBase(
PluginDescription()
.mainType(PluginType.PUMP)
@@ -205,7 +208,7 @@ import javax.inject.Singleton
}
override val baseBasalRate: Double
- get() = 0.0 // TODO
+ get() = medtrumPump.baseBasalRate
override val reservoirLevel: Double
get() = medtrumPump.reservoir
@@ -222,7 +225,24 @@ import javax.inject.Singleton
}
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
- return PumpEnactResult(injector) // TODO
+ if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
+
+ aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute - absoluteRate: $absoluteRate, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
+ // round rate to 0.05
+ val pumpRate = round(absoluteRate * 20) / 20 // TODO: Maybe replace by constraints thing
+ temporaryBasalStorage.add(PumpSync.PumpState.TemporaryBasal(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), pumpRate, true, tbrType, 0L, 0L))
+ val connectionOk = medtrumService?.setTempBasal(pumpRate, durationInMinutes) ?: false
+ if (connectionOk
+ && medtrumPump.tempBasalInProgress
+ && Math.abs(medtrumPump.tempBasalAbsoluteRate - pumpRate) <= 0.05
+ /*&& Math.abs(medtrumPump.tempBasalRemainingMinutes - durationInMinutes) <= 5*/) {
+
+ return PumpEnactResult(injector).success(true).enacted(true).duration(/*medtrumPump.tempBasalRemainingMinutes*/durationInMinutes).absolute(medtrumPump.tempBasalAbsoluteRate).isPercent(false)
+ .isTempCancel(false)
+ } else {
+ aapsLogger.error(LTag.PUMP, "setTempBasalAbsolute failed, connectionOk: $connectionOk, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}, tempBasalAbsoluteRate: ${medtrumPump.tempBasalAbsoluteRate}") //, tempBasalRemainingMinutes: ${medtrumPump.tempBasalRemainingMinutes}")
+ return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum setTempBasalAbsolute failed")
+ }
}
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
@@ -236,7 +256,16 @@ import javax.inject.Singleton
}
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
- return PumpEnactResult(injector) // TODO
+ if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
+
+ aapsLogger.info(LTag.PUMP, "cancelTempBasal - enforceNew: $enforceNew")
+ val connectionOk = medtrumService?.cancelTempBasal() ?: false
+ if (connectionOk && !medtrumPump.tempBasalInProgress) {
+ return PumpEnactResult(injector).success(true).enacted(true).isTempCancel(true)
+ } else {
+ aapsLogger.error(LTag.PUMP, "cancelTempBasal failed, connectionOk: $connectionOk, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}")
+ return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum cancelTempBasal failed")
+ }
}
override fun cancelExtendedBolus(): PumpEnactResult {
@@ -289,8 +318,4 @@ import javax.inject.Singleton
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
}
-
- private fun readTBR(): PumpSync.PumpState.TemporaryBasal? {
- return pumpSync.expectedPumpState().temporaryBasal // TODO
- }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 6791190162..a365e8e3bd 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -1,16 +1,22 @@
package info.nightscout.pump.medtrum
+import android.util.Base64
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.profile.Profile
+import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.pump.TemporaryBasalStorage
import info.nightscout.interfaces.pump.defs.PumpType
import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
+import info.nightscout.shared.utils.T
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
@@ -21,7 +27,9 @@ import kotlin.math.round
class MedtrumPump @Inject constructor(
private val aapsLogger: AAPSLogger,
private val sp: SP,
- private val dateUtil: DateUtil
+ private val dateUtil: DateUtil,
+ private val pumpSync: PumpSync,
+ private val temporaryBasalStorage: TemporaryBasalStorage
) {
// Connection state flow
@@ -33,6 +41,14 @@ class MedtrumPump @Inject constructor(
_connectionState.value = value
}
+ /** Patch activated state, mainly for UI, but also controls the connection flow,
+ * if patch is not activated, AAPS cannot connect to the pump, we can then connect trough the activation flow.
+ * Note: this is also saved in SP, by the set functions
+ */
+ private var _patchActivated = false
+ val patchActivated: Boolean
+ get() = _patchActivated
+
// Pump state flow
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
val pumpStateFlow: StateFlow = _pumpState
@@ -42,10 +58,6 @@ class MedtrumPump @Inject constructor(
_pumpState.value = value
}
- var _patchActivated = false
- val patchActivated: Boolean
- get() = _patchActivated
-
// Prime progress as state flow
private val _primeProgress = MutableStateFlow(0)
val primeProgressFlow: StateFlow = _primeProgress
@@ -55,14 +67,62 @@ class MedtrumPump @Inject constructor(
_primeProgress.value = value
}
- var pumpSN = 0L
- val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection
- var patchSessionToken = 0L
+ /** Stuff stored in SP */
+ private var _patchSessionToken = 0L
+ var patchSessionToken: Long
+ get() = _patchSessionToken
+ set(value) {
+ _patchSessionToken = value
+ sp.putLong(R.string.key_session_token, value)
+ }
+
+ private var _patchId = 0L
+ var patchId: Long
+ get() = _patchId
+ set(value) {
+ _patchId = value
+ sp.putLong(R.string.key_patch_id, value)
+ }
+
+ private var _currentSequenceNumber = 0
+ var currentSequenceNumber: Int
+ get() = _currentSequenceNumber
+ set(value) {
+ _currentSequenceNumber = value
+ sp.putInt(R.string.key_current_sequence_number, value)
+ }
+
+ private var _syncedSequenceNumber = 0
+ var syncedSequenceNumber: Int
+ get() = _syncedSequenceNumber
+ set(value) {
+ _syncedSequenceNumber = value
+ sp.putInt(R.string.key_synced_sequence_number, value)
+ }
+
+ private var _actualBasalProfile = byteArrayOf(0)
+ var actualBasalProfile: ByteArray
+ get() = _actualBasalProfile
+ set(value) {
+ _actualBasalProfile = value
+ val encodedString = Base64.encodeToString(value, Base64.DEFAULT)
+ sp.putString(R.string.key_actual_basal_profile, encodedString)
+ }
+
+ private var _lastBasalType: BasalType = BasalType.NONE
+ var lastBasalType: BasalType
+ get() = _lastBasalType
+ set(value) {
+ _lastBasalType = value
+ sp.putInt(R.string.key_last_basal_type, value.ordinal)
+ }
+
+ private var _pumpSN = 0L
+ val pumpSN: Long
+ get() = _pumpSN
+
+ val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection
- // TODO: Save this in SP? This might be a bit tricky as we only know what we have set, not what the pump has set but the pump should not change it, addtionally we should track the active basal profile in pump e.g. Basal patern A, B etc
- var actualBasalProfile = byteArrayOf(0)
- var patchId = 0L
- var lastKnownSequenceNumber = 0
var lastTimeReceivedFromPump = 0L // Time in seconds!
var suspendTime = 0L // Time in seconds!
var patchStartTime = 0L // Time in seconds!
@@ -76,16 +136,25 @@ class MedtrumPump @Inject constructor(
var alarmFlags = 0
var alarmParameter = 0
- // Last basal status update
- var lastBasalType = 0
+ // Last basal status update
+ // TODO: Save this in SP?
var lastBasalRate = 0.0
var lastBasalSequence = 0
- var lastBasalPatchId = 0
+ var lastBasalPatchId = 0L
var lastBasalStartTime = 0L
+ val baseBasalRate: Double
+ get() = getCurrentHourlyBasalFromMedtrumProfileArray(actualBasalProfile)
+
+ // TBR status
+ val tempBasalInProgress: Boolean
+ get() = lastBasalType == BasalType.ABSOLUTE_TEMP || lastBasalType == BasalType.RELATIVE_TEMP
+ val tempBasalAbsoluteRate: Double
+ get() = if (tempBasalInProgress) lastBasalRate else 0.0
+
// Last stop status update
var lastStopSequence = 0
- var lastStopPatchId = 0
+ var lastStopPatchId = 0L
// TODO set these setting on init
// User settings (desired values, to be set on pump)
@@ -94,6 +163,45 @@ class MedtrumPump @Inject constructor(
var desiredHourlyMaxInsulin: Int = 40
var desiredDailyMaxInsulin: Int = 180
+ init {
+ // Load stuff from SP
+ _patchActivated = sp.getBoolean(R.string.key_patch_activated, false)
+ _patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
+ _currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
+ _patchId = sp.getLong(R.string.key_patch_id, 0L)
+ _syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
+ _lastBasalType = enumValues()[sp.getInt(R.string.key_last_basal_type, 0)]
+
+ val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
+ try {
+ _actualBasalProfile = Base64.decode(encodedString, Base64.DEFAULT)
+ } catch (e: Exception) {
+ aapsLogger.error(LTag.PUMP, "Error decoding basal profile from SP: $encodedString")
+ }
+
+ if (patchActivated) {
+ aapsLogger.debug(LTag.PUMP, "changePump: Patch is already activated, setting as ACTIVE")
+ // Set inital status as active will be updated on first connection
+ pumpState = MedtrumPumpState.ACTIVE
+ }
+
+ loadUserSettingsFromSP()
+ }
+
+ fun loadUserSettingsFromSP() {
+ // TODO
+ // desiredPatchExpiration = sp.getBoolean(R.string.key_patch_expiration, false)
+ // desiredAlarmSetting = sp.getInt(R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code)
+ // desiredHourlyMaxInsulin = sp.getInt(R.string.key_hourly_max_insulin, 40)
+ // desiredDailyMaxInsulin = sp.getInt(R.string.key_daily_max_insulin, 180)
+
+ try {
+ _pumpSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
+ } catch (e: NumberFormatException) {
+ aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
+ }
+ }
+
fun setPatchActivatedState(activated: Boolean) {
aapsLogger.debug(LTag.PUMP, "setPatchActivatedState: $activated")
_patchActivated = activated
@@ -101,7 +209,8 @@ class MedtrumPump @Inject constructor(
}
/** When the activation/deactivation screen, and the connection flow needs to be controlled,
- * this can be used to set the ActivatedState without saving to SP, So when app is force closed the state is still maintained */
+ * this can be used to set the ActivatedState without saving to SP, So when app is force closed the state is still maintained
+ */
fun setPatchActivatedStateTemp(activated: Boolean) {
aapsLogger.debug(LTag.PUMP, "setPatchActivatedStateTemp: $activated")
_patchActivated = activated
@@ -123,29 +232,109 @@ class MedtrumPump @Inject constructor(
return (list.size).toByteArray(1) + basals
}
- fun handleBasalStatusUpdate(basalType: Int, basalValue: Double, basalSequence: Int, basalPatchId: Int, basalStartTime: Long) {
+ fun getCurrentHourlyBasalFromMedtrumProfileArray(basalProfile: ByteArray): Double {
+ val basalCount = basalProfile[0].toInt()
+ var basal = 0.0
+ if (basalProfile.size < 4 || (basalProfile.size - 1) % 3 != 0 || basalCount > 24) {
+ aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: No valid basal profile set")
+ return basal
+ }
+
+ val hourOfDayMinutes = dateUtil.dateAndTimeString(dateUtil.now()).substring(11, 13).toInt() * 60 + dateUtil.dateAndTimeString(dateUtil.now()).substring(14, 16).toInt()
+
+ for (index in 0 until basalCount) {
+ val currentIndex = 1 + (index * 3)
+ val nextIndex = currentIndex + 3
+ val rateAndTime = basalProfile.copyOfRange(currentIndex, nextIndex).toInt()
+ val rate = (rateAndTime shr 12) * 0.05
+ val startMinutes = rateAndTime and 0xFFF
+
+ val endMinutes = if (nextIndex < basalProfile.size) {
+ val nextRateAndTime = basalProfile.copyOfRange(nextIndex, nextIndex + 3).toInt()
+ nextRateAndTime and 0xFFF
+ } else {
+ 24 * 60
+ }
+
+ if (hourOfDayMinutes in startMinutes until endMinutes) {
+ basal = rate
+ aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: basal: $basal")
+ break
+ }
+ aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: rate: $rate, startMinutes: $startMinutes, endMinutes: $endMinutes")
+ }
+ return basal
+ }
+
+ fun handleBasalStatusUpdate(basalType: BasalType, basalValue: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long) {
handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now())
}
- fun handleBasalStatusUpdate(basalType: Int, basalRate: Double, basalSequence: Int, basalPatchId: Int, basalStartTime: Long, receivedTime: Long) {
+ fun handleBasalStatusUpdate(basalType: BasalType, basalRate: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long, receivedTime: Long) {
aapsLogger.debug(
- LTag.PUMP, "handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " +
- "receivedTime: $receivedTime"
+ LTag.PUMP,
+ "handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + "receivedTime: $receivedTime"
)
+ if (basalType.isTempBasal()) {
+ // TODO: Is this the correct place to sync temporaryBasalInfo? Note: it will be removed after getting it once, So this would only apply when called in setTempBasalPacket, maybe first check if basal entry already exists and leave this here, then we can also let the onNotification stuff sync basal?
+ val temporaryBasalInfo = temporaryBasalStorage.findTemporaryBasal(basalStartTime, basalRate)
+
+ // If duration is unknown, no way to get it now, set patch lifetime as duration
+ val duration = temporaryBasalInfo?.duration ?: T.mins(4800).msecs()
+ val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
+ timestamp = basalStartTime,
+ rate = basalRate, // TODO: Support percent here, this will break things? Check if this is correct
+ duration = duration,
+ isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
+ type = temporaryBasalInfo?.type,
+ pumpId = basalStartTime,
+ pumpType = pumpType,
+ pumpSerial = pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " + "Rate: $basalRate Duration: ${duration}min"
+ )
+ } else if (basalType.isSuspendedByPump()) {
+ val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
+ timestamp = basalStartTime,
+ rate = 0.0,
+ duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER
+ isAbsolute = true,
+ type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
+ pumpId = basalStartTime,
+ pumpType = pumpType,
+ pumpSerial = pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime)"
+ )
+ }
+
+ // Update medtrum pump state
lastBasalType = basalType
lastBasalRate = basalRate
lastBasalSequence = basalSequence
- lastKnownSequenceNumber = basalSequence
+ if (basalSequence > currentSequenceNumber) {
+ currentSequenceNumber = basalSequence
+ }
lastBasalPatchId = basalPatchId
+ if (basalPatchId != patchId) {
+ aapsLogger.error(LTag.PUMP, "handleBasalStatusUpdate: WTF? PatchId in status update does not match current patchId!")
+ }
lastBasalStartTime = basalStartTime
- // TODO Handle history
}
- fun handleStopStatusUpdate(stopSequence: Int, stopPatchId: Int) {
+ fun handleStopStatusUpdate(stopSequence: Int, stopPatchId: Long) {
aapsLogger.debug(LTag.PUMP, "handleStopStatusUpdate: stopSequence: $stopSequence stopPatchId: $stopPatchId")
lastStopSequence = stopSequence
- lastKnownSequenceNumber = stopSequence
+ if (stopSequence > currentSequenceNumber) {
+ currentSequenceNumber = stopSequence
+ }
lastStopPatchId = stopPatchId
- // TODO Handle history
+ if (stopPatchId != patchId) {
+ aapsLogger.error(LTag.PUMP, "handleStopStatusUpdate: WTF? PatchId in status update does not match current patchId!")
+ }
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BasalType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BasalType.kt
new file mode 100644
index 0000000000..7379b03609
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BasalType.kt
@@ -0,0 +1,58 @@
+package info.nightscout.pump.medtrum.comm.enums
+
+enum class BasalType {
+ NONE,
+ STANDARD,
+ EXERCISE,
+ HOLIDAY,
+ PROGRAM_A,
+ PROGRAM_B,
+ ABSOLUTE_TEMP,
+ RELATIVE_TEMP,
+ PROGRAM_C,
+ PROGRAM_D,
+ SICK,
+ AUTO,
+ NEW,
+ SUSPEND_LOW_GLUCOSE,
+ SUSPEND_PREDICT_LOW_GLUCOSE,
+ SUSPEND_AUTO,
+ SUSPEND_MORE_THAN_MAX_PER_HOUR,
+ SUSPEND_MORE_THAN_MAX_PER_DAY,
+ SUSPEND_MANUAL,
+ SUSPEND_KEY_LOST,
+ STOP_OCCLUSION,
+ STOP_EXPIRED,
+ STOP_EMPTY,
+ STOP_PATCH_FAULT,
+ STOP_PATCH_FAULT2,
+ STOP_BASE_FAULT,
+ STOP_DISCARD,
+ STOP_BATTERY_EXHAUSTED,
+ STOP,
+ PAUSE_INTERRUPT,
+ PRIME,
+ AUTO_MODE_START,
+ AUTO_MODE_EXIT,
+ AUTO_MODE_TARGET_100,
+ AUTO_MODE_TARGET_110,
+ AUTO_MODE_TARGET_120,
+ AUTO_MODE_BREAKFAST,
+ AUTO_MODE_LUNCH,
+ AUTO_MODE_DINNER,
+ AUTO_MODE_SNACK,
+ AUTO_MODE_EXERCISE_START,
+ AUTO_MODE_EXERCISE_EXIT;
+
+ fun getValue(): Int {
+ return ordinal
+ }
+
+ fun isTempBasal(): Boolean {
+ return this == ABSOLUTE_TEMP || this == RELATIVE_TEMP
+ }
+
+ fun isSuspendedByPump(): Boolean {
+ return this in SUSPEND_LOW_GLUCOSE..STOP
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
index 6b5c00d117..627c7f2344 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
@@ -5,6 +5,7 @@ import info.nightscout.interfaces.pump.DetailedBolusInfo
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.ACTIVATE
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toByte
import info.nightscout.interfaces.stats.TddCalculator
@@ -85,15 +86,17 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
val medtrumTimeUtil = MedtrumTimeUtil()
val patchId = data.copyOfRange(RESP_PATCH_ID_START, RESP_PATCH_ID_END).toLong()
- val time = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
- val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
+ val time = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
+ val basalType = enumValues()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
val basalValue = data.copyOfRange(RESP_BASAL_VALUE_START, RESP_BASAL_VALUE_END).toInt() * 0.05
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
- val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
- val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+ val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
+ val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
medtrumPump.patchId = patchId
medtrumPump.lastTimeReceivedFromPump = time
+ medtrumPump.currentSequenceNumber = basalSequence // We are activated, set the new seq nr
+ medtrumPump.syncedSequenceNumber = basalSequence // We are activated, reset the synced seq nr ()
// Update the actual basal profile
medtrumPump.actualBasalProfile = basalProfile
// TODO: Handle history entry
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
index 0f5aa165db..d5ca93c993 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
@@ -3,9 +3,11 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.CANCEL_TEMP_BASAL
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import info.nightscout.rx.logging.LTag
import javax.inject.Inject
class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@@ -34,11 +36,11 @@ class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(inject
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
+ val basalType = enumValues()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
- val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
- val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+ val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
+ val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
index 9aa9c2e2be..d817895fa5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -1,16 +1,26 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
+import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.pump.TemporaryBasalStorage
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
+import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.utils.DateUtil
+import info.nightscout.shared.utils.T
import javax.inject.Inject
class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int) : MedtrumPacket(injector) {
@Inject lateinit var medtrumPump: MedtrumPump
+ @Inject lateinit var pumpSync: PumpSync
+ @Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
+ @Inject lateinit var dateUtil: DateUtil
companion object {
@@ -20,11 +30,29 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
private const val RESP_RECORD_UNKNOWN_END = RESP_RECORD_UNKNOWN_START + 1
private const val RESP_RECORD_TYPE_START = RESP_RECORD_UNKNOWN_END
private const val RESP_RECORD_TYPE_END = RESP_RECORD_TYPE_START + 1
- private const val RESP_RECORD_SERIAL_START = RESP_RECORD_TYPE_END
+ private const val RESP_RECORD_UNKNOWN1_START = RESP_RECORD_TYPE_END
+ private const val RESP_RECORD_UNKNOWN1_END = RESP_RECORD_UNKNOWN1_START + 1
+ private const val RESP_RECORD_SERIAL_START = RESP_RECORD_UNKNOWN1_END
private const val RESP_RECORD_SERIAL_END = RESP_RECORD_SERIAL_START + 4
private const val RESP_RECORD_PATCHID_START = RESP_RECORD_SERIAL_END
private const val RESP_RECORD_PATCHID_END = RESP_RECORD_PATCHID_START + 2
- private const val RESP_RECORD_DATA_START = RESP_RECORD_PATCHID_END
+ private const val RESP_RECORD_SEQUENCE_START = RESP_RECORD_PATCHID_END
+ private const val RESP_RECORD_SEQUENCE_END = RESP_RECORD_SEQUENCE_START + 2
+ private const val RESP_RECORD_DATA_START = RESP_RECORD_SEQUENCE_END
+
+ private const val VALID_HEADER = 170
+ private const val BOLUS_RECORD = 1
+ private const val BOLUS_RECORD_ALT = 65
+ private const val BASAL_RECORD = 2
+ private const val BASAL_RECORD_ALT = 66
+ private const val ALARM_RECORD = 3
+ private const val AUTO_RECORD = 4
+ private const val TIME_SYNC_RECORD = 5
+ private const val AUTO1_RECORD = 6
+ private const val AUTO2_RECORD = 7
+ private const val AUTO3_RECORD = 8
+ private const val TDD_RECORD = 9
+
}
init {
@@ -44,8 +72,137 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
val recordType = data.copyOfRange(RESP_RECORD_TYPE_START, RESP_RECORD_TYPE_END).toInt()
val recordSerial = data.copyOfRange(RESP_RECORD_SERIAL_START, RESP_RECORD_SERIAL_END).toLong()
val recordPatchId = data.copyOfRange(RESP_RECORD_PATCHID_START, RESP_RECORD_PATCHID_END).toInt()
+ val recordSequence = data.copyOfRange(RESP_RECORD_SEQUENCE_START, RESP_RECORD_SEQUENCE_END).toInt()
- // TODO Handle history records
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "GetRecordPacket HandleResponse: Record header: $recordHeader, unknown: $recordUnknown, type: $recordType, serial: $recordSerial, patchId: $recordPatchId, " + "sequence: $recordSequence"
+ )
+
+ medtrumPump.syncedSequenceNumber = recordSequence // Assume sync upwards
+
+ if (recordHeader == VALID_HEADER) {
+ when (recordType) {
+ BOLUS_RECORD, BOLUS_RECORD_ALT -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD")
+ }
+
+ BASAL_RECORD, BASAL_RECORD_ALT -> {
+ val medtrumTimeUtil = MedtrumTimeUtil()
+ val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START, RESP_RECORD_DATA_START + 4).toLong())
+ val basalEndTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START + 4, RESP_RECORD_DATA_START + 8).toLong())
+ val basalType = enumValues()[data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 9).toInt()]
+ val basalEndReason = data.copyOfRange(RESP_RECORD_DATA_START + 9, RESP_RECORD_DATA_START + 10).toInt()
+ val basalRate = data.copyOfRange(RESP_RECORD_DATA_START + 10, RESP_RECORD_DATA_START + 12).toInt() * 0.05
+ val basalDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 14).toInt() * 0.05
+ val basalPercent = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toInt()
+
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "GetRecordPacket HandleResponse: BASAL_RECORD: Start: $basalStartTime, End: $basalEndTime, Type: $basalType, EndReason: $basalEndReason, Rate: $basalRate, Delivered: $basalDelivered, Percent: $basalPercent"
+ )
+
+ when (basalType) {
+ BasalType.STANDARD -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Standard basal")
+ // If we are here it means the basal has ended
+ }
+
+ BasalType.ABSOLUTE_TEMP, BasalType.RELATIVE_TEMP -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Absolute temp basal")
+ val duration = (basalEndTime - basalStartTime)
+ if (duration > 0) { // Sync start and end
+ val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
+ timestamp = basalStartTime,
+ rate = if (basalType == BasalType.ABSOLUTE_TEMP) basalRate else basalPercent.toDouble(),
+ duration = duration,
+ isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
+ type = PumpSync.TemporaryBasalType.NORMAL,
+ pumpId = basalStartTime,
+ pumpType = medtrumPump.pumpType,
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_SYNC: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
+ "Rate: $basalRate Duration: ${duration}min"
+ )
+ } else { // Sync only end ?
+ pumpSync.syncStopTemporaryBasalWithPumpId(
+ timestamp = basalEndTime,
+ endPumpId = basalEndTime,
+ pumpType = medtrumPump.pumpType,
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ aapsLogger.warn(
+ LTag.PUMPCOMM,
+ "handleBasalStatusUpdate from record: EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalEndTime)} ($basalEndTime) " + "Rate: $basalRate Duration: ${duration}min"
+ )
+ }
+ }
+ in BasalType.SUSPEND_LOW_GLUCOSE..BasalType.STOP -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Suspend basal")
+ val duration = (basalEndTime - basalStartTime)
+ val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
+ timestamp = basalEndTime,
+ rate = 0.0,
+ duration = duration,
+ isAbsolute = true,
+ type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
+ pumpId = basalStartTime,
+ pumpType = medtrumPump.pumpType,
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT SUSPEND: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
+ "Rate: $basalRate Duration: ${duration}min"
+ )
+
+ }
+ else -> {
+ aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Unknown basal type: $basalType")
+ // TODO: Error warning
+ }
+ }
+ }
+
+ ALARM_RECORD -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: ALARM_RECORD")
+ }
+
+ AUTO_RECORD -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO_RECORD")
+ }
+
+ TIME_SYNC_RECORD -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: TIME_SYNC_RECORD")
+ }
+
+ AUTO1_RECORD -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO1_RECORD")
+ }
+
+ AUTO2_RECORD -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO2_RECORD")
+ }
+
+ AUTO3_RECORD -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO3_RECORD")
+ }
+
+ TDD_RECORD -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: TDD_RECORD")
+ }
+
+ else -> {
+ aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: Unknown record type: $recordType")
+ }
+ }
+
+ } else {
+ aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: Invalid record header")
+ }
}
return success
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
index cedaf6fdbe..45efb5c30b 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacket.kt
@@ -25,7 +25,7 @@ class GetTimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- val time = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
+ val time = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
medtrumPump.lastTimeReceivedFromPump = time
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index 3898488ea4..37f9ec0465 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -2,6 +2,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
@@ -98,7 +99,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
var bolusType = bolusData and 0x7F
var bolusCompleted = (bolusData shr 7) and 0x01 // TODO: Check for other flags here :)
- var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() / 0.05
+ var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() * 0.05
// TODO Sync bolus flow:
// If bolus is known add status
// If bolus is not known start read bolus
@@ -115,18 +116,20 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_BASAL != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Basal notification received")
- var basalType = data.copyOfRange(offset, offset + 1).toInt()
+ val basalType = enumValues()[data.copyOfRange(offset, offset + 1).toInt()]
var basalSequence = data.copyOfRange(offset + 1, offset + 3).toInt()
- var basalPatchId = data.copyOfRange(offset + 3, offset + 5).toInt()
- var basalInterval = data.copyOfRange(offset + 5, offset + 9).toInt()
+ var basalPatchId = data.copyOfRange(offset + 3, offset + 5).toLong()
+ var basalTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset + 5, offset + 9).toLong())
var basalRateAndDelivery = data.copyOfRange(offset + 9, offset + 12).toInt()
var basalRate = (basalRateAndDelivery and 0xFFF) * 0.05
var basalDelivery = (basalRateAndDelivery shr 12) * 0.05
aapsLogger.debug(
LTag.PUMPCOMM,
- "Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal interval: $basalInterval, basal rate: $basalRate, basal delivery: $basalDelivery"
+ "Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal time: $basalTime, basal rate: $basalRate, basal delivery: $basalDelivery"
)
- // TODO Sync basal flow
+ // TODO: Check if basal is known, if not add it
+ // medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalTime)
+ // TODO: Handle basal delivery
offset += 12
}
@@ -165,9 +168,16 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_STORAGE != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Storage notification received")
// TODO, trigger check for new sequence?
- medtrumPump.lastKnownSequenceNumber = data.copyOfRange(offset, offset + 2).toInt()
- medtrumPump.patchId = data.copyOfRange(offset + 2, offset + 4).toLong()
- aapsLogger.debug(LTag.PUMPCOMM, "Last known sequence number: ${medtrumPump.lastKnownSequenceNumber}, patch id: ${medtrumPump.patchId}")
+ val sequence = data.copyOfRange(offset, offset + 2).toInt()
+ if (sequence > medtrumPump.currentSequenceNumber) {
+ medtrumPump.currentSequenceNumber = sequence
+ }
+ val patchId = data.copyOfRange(offset + 2, offset + 4).toLong()
+ if (patchId != medtrumPump.patchId) {
+ aapsLogger.error(LTag.PUMPCOMM, "handleMaskedMessage: WTF? We got wrong patch id!")
+ // TODO: We should terminate session or stop patch here? or at least throw error? THis can be thrown during activation process though
+ }
+ aapsLogger.debug(LTag.PUMPCOMM, "Last known sequence number: ${medtrumPump.currentSequenceNumber}, patch id: ${patchId}")
offset += 4
}
@@ -182,7 +192,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_START_TIME != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Start time notification received")
- medtrumPump.patchStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(offset, offset + 4).toLong())
+ medtrumPump.patchStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset, offset + 4).toLong())
aapsLogger.debug(LTag.PUMPCOMM, "Patch start time: ${medtrumPump.patchStartTime}")
offset += 4
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
index 6023a2fafb..8d7a400ea5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
@@ -3,6 +3,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BASAL_PROFILE
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
@@ -41,11 +42,11 @@ class SetBasalProfilePacket(injector: HasAndroidInjector, private val basalProfi
val success = super.handleResponse(data)
if (success) {
val medtrumTimeUtil = MedtrumTimeUtil()
- val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
+ val basalType = enumValues()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
val basalValue = data.copyOfRange(RESP_BASAL_VALUE_START, RESP_BASAL_VALUE_END).toInt() * 0.05
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
- val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
- val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+ val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
+ val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
// Update the actual basal profile
medtrumPump.actualBasalProfile = basalProfile
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
index 3d11c0ecba..f203f21a4d 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
@@ -3,10 +3,12 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_TEMP_BASAL
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import info.nightscout.rx.logging.LTag
import javax.inject.Inject
import kotlin.math.round
@@ -49,11 +51,19 @@ class SetTempBasalPacket(injector: HasAndroidInjector, private val absoluteRate:
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- val basalType = data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()
+ val basalType = enumValues()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
- val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toInt()
- val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+ val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
+
+ val rawTime = data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong()
+ val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
+ aapsLogger.debug(LTag.PUMPCOMM, "Basal status update: type=$basalType, rate=$basalRate, sequence=$basalSequence, patchId=$basalPatchId, startTime=$basalStartTime, rawTime=$rawTime")
+
+ // TODO: For debugging remove later
+ val pumpTime = MedtrumTimeUtil().getCurrentTimePumpSeconds()
+ val systemTime = System.currentTimeMillis()
+ aapsLogger.debug(LTag.PUMPCOMM, "Pump time: $pumpTime, System time: $systemTime")
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
index 9eb38417b0..dba47867a5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacket.kt
@@ -4,6 +4,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.comm.enums.CommandType.STOP_PATCH
+import info.nightscout.pump.medtrum.extension.toLong
import javax.inject.Inject
class StopPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@@ -27,7 +28,7 @@ class StopPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
val success = super.handleResponse(data)
if (success) {
val stopSequence = data.copyOfRange(RESP_STOP_SEQUENCE_START, RESP_STOP_SEQUENCE_END).toInt()
- val stopPatchId = data.copyOfRange(RESP_STOP_PATCH_ID_START, RESP_STOP_PATCH_ID_END).toInt()
+ val stopPatchId = data.copyOfRange(RESP_STOP_PATCH_ID_START, RESP_STOP_PATCH_ID_END).toLong()
medtrumPump.handleStopStatusUpdate(stopSequence, stopPatchId)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 71c566ee38..19459453fc 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -116,8 +116,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun startPrime(): Boolean {
- val packet = PrimePacket(injector)
- return sendPacketAndGetResponse(packet)
+ return sendPacketAndGetResponse(PrimePacket(injector))
}
fun startActivate(): Boolean {
@@ -141,18 +140,19 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun readPumpStatus() {
- // TODO read pump history
- }
+ // TODO decide what we need to do here
+ var result = false
- fun loadEvents(): PumpEnactResult {
- if (!medtrumPlugin.isInitialized()) {
- val result = PumpEnactResult(injector).success(false)
- result.comment = "pump not initialized"
- return result
+ // Most of these things are already done when a connection is setup, but wo dont know how long the pump was connected for?
+ // So just do a syncronize to make sure we have the latest data
+ result = sendPacketAndGetResponse(SynchronizePacket(injector))
+
+ // Sync records (based on the info we have from the sync)
+ if (result) result = syncRecords()
+ if (!result) {
+ aapsLogger.error(LTag.PUMPCOMM, "Failed to sync records")
+ return
}
- // TODO need this? Check
- val result = PumpEnactResult(injector)
- return result
}
fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean {
@@ -165,24 +165,59 @@ class MedtrumService : DaggerService(), BLECommCallback {
// TODO
}
+ fun setTempBasal(absoluteRate: Double, durationInMinutes: Int): Boolean {
+ var result = true
+ if (medtrumPump.tempBasalInProgress) {
+ result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
+ }
+ if (result) result = sendPacketAndGetResponse(SetTempBasalPacket(injector, absoluteRate, durationInMinutes))
+
+ // Get history records, this will update the pump state
+ if (result) result = syncRecords()
+
+ return result
+ }
+
+ fun cancelTempBasal(): Boolean {
+ var result = false
+
+ result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
+
+ // Get history records, this will update the pump state
+ if (result) result = syncRecords()
+
+ return result
+ }
+
fun updateBasalsInPump(profile: Profile): Boolean {
+ var result = false
val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
- return packet?.let { sendPacketAndGetResponse(it) } == true
+ result = packet?.let { sendPacketAndGetResponse(it) } == true
+
+ // TODO: We might want to get rid of this and cancel the TBR before we set the basal profile
+ // Update basal affects the TBR records (the pump will cancel the TBR, set our basal profile, and resume the TBR in a new record)
+ // Get history records, this will update the pump state and add changes in TBR to AAPS history
+ if (result) result = syncRecords()
+
+ return result
}
fun changePump() {
aapsLogger.debug(LTag.PUMP, "changePump: called!")
- try {
- medtrumPump.pumpSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
- } catch (e: NumberFormatException) {
- aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
- }
- medtrumPump.setPatchActivatedState(sp.getBoolean(R.string.key_patch_activated, false))
- medtrumPump.patchSessionToken = sp.getLong(R.string.key_session_token, 0)
- if (medtrumPump.patchActivated) {
- aapsLogger.debug(LTag.PUMP, "changePump: Patch is already activated, setting as ACTIVE")
- medtrumPump.pumpState = MedtrumPumpState.ACTIVE // Set inital status as active will be updated on first connection
+ medtrumPump.loadUserSettingsFromSP()
+ }
+
+ /** This gets the history records from the pump */
+ private fun syncRecords(): Boolean {
+ aapsLogger.debug(LTag.PUMP, "syncRecords: called!, syncedSequenceNumber: ${medtrumPump.syncedSequenceNumber}, currentSequenceNumber: ${medtrumPump.currentSequenceNumber}")
+ var result = false
+ // TODO: Check if we need to sync older records as well
+ // Note: medtrum app fetches all records when they sync?
+ for (sequence in medtrumPump.syncedSequenceNumber..medtrumPump.currentSequenceNumber) {
+ result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
+ if (!result) break
}
+ return result
}
/** BLECommCallbacks */
@@ -206,7 +241,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onSendMessageError(reason: String) {
aapsLogger.debug(LTag.PUMPCOMM, "<<<<< error during send message $reason")
- // TODO
+ currentState.onSendMessageError(reason)
}
/** Service stuff */
@@ -270,6 +305,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
open fun waitForResponse(): Boolean {
return false
}
+
+ open fun onSendMessageError(reason: String) {
+ aapsLogger.debug(LTag.PUMPCOMM, "onSendMessageError: " + this.toString() + "reason: $reason")
+ }
}
private inner class IdleState : State() {
@@ -350,16 +389,18 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
- val currTimeSec = dateUtil.nowWithoutMilliseconds() / 1000
- if (abs(timeUtil.convertPumpTimeToSystemTimeSeconds(medtrumPump.lastTimeReceivedFromPump) - currTimeSec) <= 5) { // Allow 5 sec deviation
+ val currTime = dateUtil.nowWithoutMilliseconds()
+ if (abs(medtrumPump.lastTimeReceivedFromPump - currTime) <= T.secs(5).msecs()) { // Allow 5 sec deviation
toState(SynchronizeState())
} else {
aapsLogger.debug(
LTag.PUMPCOMM,
- "GetTimeState.onIndication need to set time. systemTime: $currTimeSec PumpTime: ${medtrumPump.lastTimeReceivedFromPump} Pump Time to system time: " + timeUtil.convertPumpTimeToSystemTimeSeconds(
+ "GetTimeState.onIndication need to set time. systemTime: $currTime PumpTime: ${medtrumPump.lastTimeReceivedFromPump} Pump Time to system time: " + timeUtil
+ .convertPumpTimeToSystemTimeMillis(
medtrumPump.lastTimeReceivedFromPump
)
)
+ // TODO: Setting time cancels any TBR, so we need to handle that and cancel? or let AAPS handle time syncs?
toState(SetTimeState())
}
} else if (mPacket?.failed == true) {
@@ -497,6 +538,12 @@ class MedtrumService : DaggerService(), BLECommCallback {
responseSuccess = false
}
+ override fun onSendMessageError(reason: String) {
+ super.onSendMessageError(reason)
+ responseHandled = true
+ responseSuccess = false
+ }
+
override fun waitForResponse(): Boolean {
val startTime = System.currentTimeMillis()
val timeoutMillis = T.secs(45).msecs()
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index 66c66249e0..2e5503df3f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -46,9 +46,9 @@ class MedtrumOverviewFragment : MedtrumBaseFragment requireContext().apply {
val step = convertToPatchStep(medtrumPump.pumpState)
// TODO is stil needed?
- if (step != PatchStep.PREPARE_PATCH) {
- aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step")
- }
+ // if (step != PatchStep.PREPARE_PATCH) {
+ // aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step")
+ // }
startActivity(MedtrumActivity.createIntentFromMenu(this, step))
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
index 2b2650427b..70416c5d87 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
@@ -173,8 +173,7 @@ class MedtrumViewModel @Inject constructor(
}
// New session, generate new session token
aapsLogger.info(LTag.PUMP, "preparePatch: new session")
- medtrumPump.patchSessionToken = Crypt().generateRandomToken()
- sp.putLong(R.string.key_session_token, medtrumPump.patchSessionToken)
+ medtrumPump.patchSessionToken = Crypt().generateRandomToken()
// Connect to pump
medtrumService?.connect("PreparePatch")
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
index e470f90b63..ad3910f0ec 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/util/MedtrumTimeUtil.kt
@@ -11,10 +11,16 @@ class MedtrumTimeUtil {
return Duration.between(startInstant, currentInstant).seconds
}
- fun convertPumpTimeToSystemTimeSeconds(pumpTime: Long) : Long {
+ fun getCurrentTimePumpMillis() : Long {
+ val startInstant = Instant.parse("2014-01-01T00:00:00Z")
+ val currentInstant = Instant.now()
+ return Duration.between(startInstant, currentInstant).seconds * 1000
+ }
+
+ fun convertPumpTimeToSystemTimeMillis(pumpTime: Long) : Long {
val startInstant = Instant.parse("2014-01-01T00:00:00Z")
val pumpInstant = startInstant.plusSeconds(pumpTime)
val epochInstant = Instant.EPOCH
- return Duration.between(epochInstant, pumpInstant).seconds
+ return Duration.between(epochInstant, pumpInstant).seconds * 1000
}
}
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index b9081caef4..d987e70c7a 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -1,10 +1,15 @@
- snInput
- medtrumpump_settings
- medtrum_patch_activated
- medtrum_session_token
+ snInput
+ medtrumpump_settings
+ medtrum_patch_activated
+ medtrum_session_token
+ patch_id
+ actual_basal_profile
+ last_basal_type
+ current_sequence_number
+ synced_sequence_number
Medtrum
MEDTRUM
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
index b7494eb858..fe5ffd7c9d 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumTestBase.kt
@@ -4,6 +4,7 @@ import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.pump.TemporaryBasalStorage
import info.nightscout.interfaces.stats.TddCalculator
import org.junit.jupiter.api.BeforeEach
import org.mockito.Mock
@@ -14,11 +15,12 @@ open class MedtrumTestBase: TestBaseWithProfile() {
@Mock lateinit var instantiator: Instantiator
@Mock lateinit var tddCalculator: TddCalculator
@Mock lateinit var pumpSync: PumpSync
+ @Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage
lateinit var medtrumPump: MedtrumPump
@BeforeEach
fun setup() {
- medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil)
+ medtrumPump = MedtrumPump(aapsLogger, sp, dateUtil, pumpSync, temporaryBasalStorage)
}
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
index c72fcb4ecb..7c07339220 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
@@ -2,6 +2,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.MedtrumTestBase
import info.nightscout.pump.medtrum.extension.toByteArray
import org.junit.jupiter.api.Test
@@ -23,7 +24,9 @@ class AuthorizePacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketAndSNWhenCalledThenReturnAuthorizePacket() {
// Inputs
val opCode = 5
- medtrumPump.pumpSN = 2859923929
+ val _pumpSN = MedtrumPump::class.java.getDeclaredField("_pumpSN")
+ _pumpSN.isAccessible = true
+ _pumpSN.setLong(medtrumPump, 2859923929)
medtrumPump.patchSessionToken = 667
// Call
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
index 4fff76bc90..36c9751bb8 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetTimePacketTest.kt
@@ -48,7 +48,7 @@ class GetTimePacketTest : MedtrumTestBase() {
// Expected values
assertEquals(true, result)
assertEquals(false, packet.failed)
- assertEquals(MedtrumTimeUtil().convertPumpTimeToSystemTimeSeconds(time), medtrumPump.lastTimeReceivedFromPump)
+ assertEquals(MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(time), medtrumPump.lastTimeReceivedFromPump)
}
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
From a9ebdcfe68160f03762c725bc315374aaea72b4e Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 23 May 2023 10:20:22 +0200
Subject: [PATCH 019/116] Connection improvements, TBR sync improved
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 11 ++---
.../medtrum/comm/packets/AuthorizePacket.kt | 10 +++++
.../medtrum/comm/packets/GetRecordPacket.kt | 6 +--
.../medtrum/comm/packets/MedtrumPacket.kt | 8 ++--
.../comm/packets/NotificationPacket.kt | 4 +-
.../pump/medtrum/services/BLEComm.kt | 41 ++++++++++---------
.../pump/medtrum/services/MedtrumService.kt | 12 +++++-
7 files changed, 56 insertions(+), 36 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index a365e8e3bd..bcc4d77733 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -261,7 +261,7 @@ class MedtrumPump @Inject constructor(
aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: basal: $basal")
break
}
- aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: rate: $rate, startMinutes: $startMinutes, endMinutes: $endMinutes")
+ // aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: rate: $rate, startMinutes: $startMinutes, endMinutes: $endMinutes")
}
return basal
}
@@ -275,8 +275,9 @@ class MedtrumPump @Inject constructor(
LTag.PUMP,
"handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + "receivedTime: $receivedTime"
)
- if (basalType.isTempBasal()) {
- // TODO: Is this the correct place to sync temporaryBasalInfo? Note: it will be removed after getting it once, So this would only apply when called in setTempBasalPacket, maybe first check if basal entry already exists and leave this here, then we can also let the onNotification stuff sync basal?
+ val expectedTemporaryBasal = pumpSync.expectedPumpState().temporaryBasal
+ if (basalType.isTempBasal() && expectedTemporaryBasal?.pumpId != basalStartTime) {
+ // Note: temporaryBasalInfo will be removed from temporaryBasalStorage after this call
val temporaryBasalInfo = temporaryBasalStorage.findTemporaryBasal(basalStartTime, basalRate)
// If duration is unknown, no way to get it now, set patch lifetime as duration
@@ -293,9 +294,9 @@ class MedtrumPump @Inject constructor(
)
aapsLogger.debug(
LTag.PUMPCOMM,
- "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " + "Rate: $basalRate Duration: ${duration}min"
+ "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " + "Rate: $basalRate Duration: ${duration}"
)
- } else if (basalType.isSuspendedByPump()) {
+ } else if (basalType.isSuspendedByPump() && expectedTemporaryBasal?.pumpId != basalStartTime) {
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime,
rate = 0.0,
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
index 4cf10a580c..5125de09fa 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
@@ -2,10 +2,12 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.CommandType
import info.nightscout.pump.medtrum.comm.enums.CommandType.AUTH_REQ
import info.nightscout.pump.medtrum.encryption.Crypt
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.rx.logging.LTag
import javax.inject.Inject
class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@@ -39,6 +41,14 @@ class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
}
override fun handleResponse(data: ByteArray): Boolean {
+ if (data.size > 3) {
+ val incomingOpCode: Byte = data.copyOfRange(RESP_OPCODE_START, RESP_OPCODE_END).first()
+ if (incomingOpCode == CommandType.SUBSCRIBE.code) {
+ // TODO: Test and see if this can be removed
+ aapsLogger.error(LTag.PUMPCOMM, "handleResponse: Got subscribe response instead of authorize response, handling subscribe packet")
+ return SubscribePacket(injector).handleResponse(data)
+ }
+ }
val success = super.handleResponse(data)
if (success) {
deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
index d817895fa5..0f45e405b8 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -125,7 +125,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
aapsLogger.debug(
LTag.PUMPCOMM,
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_SYNC: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
- "Rate: $basalRate Duration: ${duration}min"
+ "Rate: $basalRate Duration: ${duration}"
)
} else { // Sync only end ?
pumpSync.syncStopTemporaryBasalWithPumpId(
@@ -136,7 +136,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
)
aapsLogger.warn(
LTag.PUMPCOMM,
- "handleBasalStatusUpdate from record: EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalEndTime)} ($basalEndTime) " + "Rate: $basalRate Duration: ${duration}min"
+ "handleBasalStatusUpdate from record: EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalEndTime)} ($basalEndTime) " + "Rate: $basalRate Duration: ${duration}"
)
}
}
@@ -156,7 +156,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
aapsLogger.debug(
LTag.PUMPCOMM,
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT SUSPEND: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
- "Rate: $basalRate Duration: ${duration}min"
+ "Rate: $basalRate Duration: ${duration}"
)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt
index 6386e988ef..6b175c06df 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/MedtrumPacket.kt
@@ -16,10 +16,10 @@ open class MedtrumPacket(protected var injector: HasAndroidInjector) {
companion object {
- private const val RESP_OPCODE_START = 1
- private const val RESP_OPCODE_END = RESP_OPCODE_START + 1
- private const val RESP_RESULT_START = 4
- private const val RESP_RESULT_END = RESP_RESULT_START + 2
+ const val RESP_OPCODE_START = 1
+ const val RESP_OPCODE_END = RESP_OPCODE_START + 1
+ const val RESP_RESULT_START = 4
+ const val RESP_RESULT_END = RESP_RESULT_START + 2
private const val RESP_WAITING = 16384
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index 37f9ec0465..ef03a67f71 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -127,9 +127,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
LTag.PUMPCOMM,
"Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal time: $basalTime, basal rate: $basalRate, basal delivery: $basalDelivery"
)
- // TODO: Check if basal is known, if not add it
- // medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalTime)
- // TODO: Handle basal delivery
+ medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalTime)
offset += 12
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 0f958790c8..12c23b15db 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -92,7 +92,6 @@ class BLEComm @Inject internal constructor(
var isConnected = false // TODO: These may be removed have no function
var isConnecting = false// TODO: These may be removed have no function
- private var retryCounter = 0
private var uartWrite: BluetoothGattCharacteristic? = null
private var uartRead: BluetoothGattCharacteristic? = null
@@ -102,6 +101,7 @@ class BLEComm @Inject internal constructor(
private var mDeviceSN: Long = 0
private var mCallback: BLECommCallback? = null
+ private var mDevice: BluetoothDevice? = null
fun setCallback(callback: BLECommCallback?) {
this.mCallback = callback
@@ -144,6 +144,7 @@ class BLEComm @Inject internal constructor(
mBluetoothAdapter?.bluetoothLeScanner?.stopScan(mScanCallback)
}
+ @Synchronized
fun connect(from: String, deviceSN: Long): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED
@@ -157,10 +158,20 @@ class BLEComm @Inject internal constructor(
aapsLogger.error("Unable to obtain a BluetoothAdapter.")
return false
}
- mDeviceSN = deviceSN
- isConnecting = true
- retryCounter = 0
- startScan()
+
+ if (mDevice != null && mDeviceSN == deviceSN) {
+ // Skip scanning and directly connect to gatt
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Skipping scan and directly connecting to gatt")
+ isConnecting = true
+ connectGatt(mDevice!!)
+ } else {
+ // Scan for device
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Scanning for device")
+ mDeviceSN = deviceSN
+ isConnecting = true
+ startScan()
+ }
+
return true
}
@@ -215,6 +226,7 @@ class BLEComm @Inject internal constructor(
if (manufacturerData?.getDeviceSN() == mDeviceSN) {
aapsLogger.debug(LTag.PUMPBTCOMM, "Found our device! deviceSN: " + manufacturerData.getDeviceSN())
stopScan()
+ mDevice = result.device
connectGatt(result.device)
}
}
@@ -376,20 +388,11 @@ class BLEComm @Inject internal constructor(
mBluetoothGatt?.discoverServices()
}, WRITE_DELAY_MILLIS)
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
- if (status == 133 && isConnecting && retryCounter < 3) {
- // Special case for status 133 when we are connecting
- // We need to close gatt and try to reconnect
- aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange status 133")
- close()
- startScan()
- retryCounter++
- } else {
- close()
- isConnected = false
- isConnecting = false
- mCallback?.onBLEDisconnected()
- aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnectedS
- }
+ close()
+ isConnected = false
+ isConnecting = false
+ mCallback?.onBLEDisconnected()
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 19459453fc..23533c744f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -329,6 +329,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
// State for connect flow, could be replaced by commandState and steps in connect()
private inner class AuthState : State() {
+ val retryCounter = 0
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached AuthState")
@@ -346,8 +347,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
toState(GetDeviceTypeState())
} else if (mPacket?.failed == true) {
// Failure
- bleComm.disconnect("Failure")
- toState(IdleState())
+ // retry twice
+ // TODO: Test and see if this can be removed
+ if (retryCounter < 2) {
+ aapsLogger.error(LTag.PUMPCOMM, "AuthState failed!, retrying")
+ mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ } else {
+ bleComm.disconnect("Failure")
+ toState(IdleState())
+ }
}
}
}
From 3027c2ffa54b4899b49e480da0711251084852f1 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 25 May 2023 13:32:24 +0200
Subject: [PATCH 020/116] Initial bolus implementation, further connection
improvements
---
pump/medtrum/build.gradle | 1 +
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 44 ++++++++++-
.../nightscout/pump/medtrum/MedtrumPump.kt | 32 +++++++-
.../pump/medtrum/comm/enums/BolusType.kt | 12 +++
.../medtrum/comm/packets/AuthorizePacket.kt | 8 --
.../medtrum/comm/packets/GetRecordPacket.kt | 48 ++++++++++++
.../comm/packets/NotificationPacket.kt | 7 +-
.../pump/medtrum/services/BLEComm.kt | 33 ++++----
.../pump/medtrum/services/MedtrumService.kt | 75 +++++++++++++++----
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 13 ++++
.../res/layout/fragment_medtrum_overview.xml | 48 ++++++++++++
pump/medtrum/src/main/res/values/strings.xml | 7 +-
12 files changed, 279 insertions(+), 49 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
diff --git a/pump/medtrum/build.gradle b/pump/medtrum/build.gradle
index 6ceef5fce7..6d951eafa6 100644
--- a/pump/medtrum/build.gradle
+++ b/pump/medtrum/build.gradle
@@ -27,6 +27,7 @@ dependencies {
implementation project(':core:main')
implementation project(':core:ui')
implementation project(':core:validators')
+ implementation project(':pump:pump-common')
implementation project(':core:utils')
testImplementation project(':core:main')
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 0d2870fe36..6b7fe84598 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -8,12 +8,15 @@ import android.os.IBinder
import dagger.android.HasAndroidInjector
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.fabric.FabricPrivacy
+import info.nightscout.interfaces.constraints.Constraint
+import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.DetailedBolusInfo
+import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.pump.PumpPluginBase
@@ -52,6 +55,7 @@ import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
+import kotlin.math.abs
import kotlin.math.round
@Singleton class MedtrumPlugin @Inject constructor(
@@ -59,6 +63,7 @@ import kotlin.math.round
aapsLogger: AAPSLogger,
rh: ResourceHelper,
commandQueue: CommandQueue,
+ private val constraintChecker: Constraints,
private val sp: SP,
private val aapsSchedulers: AapsSchedulers,
private val rxBus: RxBus,
@@ -69,6 +74,7 @@ import kotlin.math.round
private val uiInteraction: UiInteraction,
private val profileFunction: ProfileFunction,
private val pumpSync: PumpSync,
+ private val detailedBolusInfoStorage: DetailedBolusInfoStorage,
private val temporaryBasalStorage: TemporaryBasalStorage
) : PumpPluginBase(
PluginDescription()
@@ -204,7 +210,7 @@ import kotlin.math.round
}
override fun lastDataTime(): Long {
- return medtrumPump.lastTimeReceivedFromPump * 1000L
+ return medtrumPump.lastTimeReceivedFromPump
}
override val baseBasalRate: Double
@@ -216,14 +222,46 @@ import kotlin.math.round
override val batteryLevel: Int
get() = 0 // TODO
+ @Synchronized
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
- return PumpEnactResult(injector) // TODO
+ aapsLogger.debug(LTag.PUMP, "deliverTreatment: " + detailedBolusInfo.insulin + "U")
+ if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
+ detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value()
+ return if (detailedBolusInfo.insulin > 0 && detailedBolusInfo.carbs == 0.0) {
+ aapsLogger.debug(LTag.PUMP, "deliverTreatment: Delivering bolus: " + detailedBolusInfo.insulin + "U")
+ detailedBolusInfoStorage.add(detailedBolusInfo) // will be picked up on reading history
+ val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.id)
+ val connectionOK = medtrumService?.setBolus(detailedBolusInfo.insulin, t) ?: false
+ val result = PumpEnactResult(injector)
+ result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep
+ result.bolusDelivered = t.insulin
+ if (!result.success) {
+ // Todo error code?
+ result.comment = "error"
+ } else {
+ result.comment = "ok"
+ }
+ aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Success: ${result.success} Asked: ${detailedBolusInfo.insulin} Delivered: ${result.bolusDelivered}")
+ result
+ } else {
+ aapsLogger.debug(LTag.PUMP, "deliverTreatment: Invalid input")
+ val result = PumpEnactResult(injector)
+ result.success = false
+ result.bolusDelivered = 0.0
+ result.comment = rh.gs(info.nightscout.core.ui.R.string.invalid_input)
+ aapsLogger.error("deliverTreatment: Invalid input")
+ result
+ }
}
override fun stopBolusDelivering() {
- // TODO
+ if (!isInitialized()) return
+
+ aapsLogger.info(LTag.PUMP, "stopBolusDelivering")
+ medtrumService?.stopBolus()
}
+ @Synchronized
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index bcc4d77733..0feda438df 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -12,6 +12,7 @@ import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
@@ -66,7 +67,15 @@ class MedtrumPump @Inject constructor(
set(value) {
_primeProgress.value = value
}
-
+
+ private val _lastBasalRate = MutableStateFlow(0.0)
+ val lastBasalRateFlow: StateFlow = _lastBasalRate
+ var lastBasalRate: Double
+ get() = _lastBasalRate.value
+ set(value) {
+ _lastBasalRate.value = value
+ }
+
/** Stuff stored in SP */
private var _patchSessionToken = 0L
var patchSessionToken: Long
@@ -136,9 +145,17 @@ class MedtrumPump @Inject constructor(
var alarmFlags = 0
var alarmParameter = 0
+ // bolus status
+ var bolusingTreatment: EventOverviewBolusProgress.Treatment? = null // actually delivered treatment
+ var bolusAmountToBeDelivered = 0.0 // amount to be delivered
+ var bolusProgressLastTimeStamp: Long = 0 // timestamp of last bolus progress message
+ var bolusStopped = false // bolus finished
+ var bolusStopForced = false // bolus forced to stop by user
+ var bolusDone = false // success end
+
// Last basal status update
// TODO: Save this in SP?
- var lastBasalRate = 0.0
+
var lastBasalSequence = 0
var lastBasalPatchId = 0L
var lastBasalStartTime = 0L
@@ -270,6 +287,17 @@ class MedtrumPump @Inject constructor(
handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now())
}
+ fun handleBolusStatusUpdate(bolusType: Int, bolusCompleted: Boolean, amountDelivered: Double) {
+ aapsLogger.debug(LTag.PUMP, "handleBolusStatusUpdate: bolusType: $bolusType bolusCompleted: $bolusCompleted amountDelivered: $amountDelivered")
+ bolusProgressLastTimeStamp = dateUtil.now()
+ if (bolusCompleted) {
+ bolusDone = true
+ bolusingTreatment?.insulin = amountDelivered
+ } else {
+ bolusingTreatment?.insulin = amountDelivered
+ }
+ }
+
fun handleBasalStatusUpdate(basalType: BasalType, basalRate: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long, receivedTime: Long) {
aapsLogger.debug(
LTag.PUMP,
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
new file mode 100644
index 0000000000..77634d5fb6
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
@@ -0,0 +1,12 @@
+package info.nightscout.pump.medtrum.comm.enums
+
+enum class BolusType {
+ NONE,
+ NORMAL,
+ EXTEND,
+ COMBINATION;
+
+ fun getValue(): Int {
+ return ordinal
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
index 5125de09fa..2093ae8cf7 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
@@ -41,14 +41,6 @@ class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
}
override fun handleResponse(data: ByteArray): Boolean {
- if (data.size > 3) {
- val incomingOpCode: Byte = data.copyOfRange(RESP_OPCODE_START, RESP_OPCODE_END).first()
- if (incomingOpCode == CommandType.SUBSCRIBE.code) {
- // TODO: Test and see if this can be removed
- aapsLogger.error(LTag.PUMPCOMM, "handleResponse: Got subscribe response instead of authorize response, handling subscribe packet")
- return SubscribePacket(injector).handleResponse(data)
- }
- }
val success = super.handleResponse(data)
if (success) {
deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
index 0f45e405b8..78eabeca96 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -1,11 +1,13 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
+import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.TemporaryBasalStorage
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD
import info.nightscout.pump.medtrum.comm.enums.BasalType
+import info.nightscout.pump.medtrum.comm.enums.BolusType
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
@@ -20,6 +22,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
@Inject lateinit var medtrumPump: MedtrumPump
@Inject lateinit var pumpSync: PumpSync
@Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
+ @Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
@Inject lateinit var dateUtil: DateUtil
companion object {
@@ -85,6 +88,51 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
when (recordType) {
BOLUS_RECORD, BOLUS_RECORD_ALT -> {
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD")
+ val typeAndWizard = data.copyOfRange(RESP_RECORD_DATA_START, RESP_RECORD_DATA_START + 1).toInt()
+ val bolusCause = data.copyOfRange(RESP_RECORD_DATA_START + 1, RESP_RECORD_DATA_START + 2).toInt()
+ val unknown = data.copyOfRange(RESP_RECORD_DATA_START + 2, RESP_RECORD_DATA_START + 4).toInt()
+ val bolusStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START + 4, RESP_RECORD_DATA_START + 8).toLong())
+ val bolusNormalAmount = data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 10).toInt() * 0.05
+ val bolusNormalDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 10, RESP_RECORD_DATA_START + 12).toInt() * 0.05
+ val bolusExtendedAmount = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 14).toInt() * 0.05
+ val bolusExtendedDuration = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toInt()
+ val bolusExtendedDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 16, RESP_RECORD_DATA_START + 18).toInt() * 0.05
+ val bolusCarb = data.copyOfRange(RESP_RECORD_DATA_START + 18, RESP_RECORD_DATA_START + 20).toInt()
+ val bolusGlucose = data.copyOfRange(RESP_RECORD_DATA_START + 20, RESP_RECORD_DATA_START + 22).toInt()
+ val bolusIOB = data.copyOfRange(RESP_RECORD_DATA_START + 22, RESP_RECORD_DATA_START + 24).toInt()
+ val unkown1 = data.copyOfRange(RESP_RECORD_DATA_START + 24, RESP_RECORD_DATA_START + 26).toInt()
+ val unkown2 = data.copyOfRange(RESP_RECORD_DATA_START + 26, RESP_RECORD_DATA_START + 28).toInt()
+ val bolusType = enumValues()[typeAndWizard and 0x0F]
+ val bolusWizard = (typeAndWizard and 0xF0) != 0
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "GetRecordPacket HandleResponse: BOLUS_RECORD: typeAndWizard: $typeAndWizard, bolusCause: $bolusCause, unknown: $unknown, bolusStartTime: $bolusStartTime, " + "bolusNormalAmount: $bolusNormalAmount, bolusNormalDelivered: $bolusNormalDelivered, bolusExtendedAmount: $bolusExtendedAmount, bolusExtendedDuration: $bolusExtendedDuration, " + "bolusExtendedDelivered: $bolusExtendedDelivered, bolusCarb: $bolusCarb, bolusGlucose: $bolusGlucose, bolusIOB: $bolusIOB, unkown1: $unkown1, unkown2: $unkown2, " + "bolusType: $bolusType, bolusWizard: $bolusWizard"
+ )
+ if (bolusType == BolusType.NORMAL) {
+ val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(bolusStartTime, bolusNormalDelivered)
+ val newRecord = pumpSync.syncBolusWithPumpId(
+ timestamp = bolusStartTime,
+ amount = bolusNormalDelivered,
+ type = detailedBolusInfo?.bolusType,
+ pumpId = bolusStartTime,
+ pumpType = medtrumPump.pumpType,
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "from record: ${if (newRecord) "**NEW** " else ""}EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U "
+ )
+ if (!newRecord && detailedBolusInfo != null) {
+ // detailedInfo can be from another similar record. Reinsert
+ detailedBolusInfoStorage.add(detailedBolusInfo)
+ }
+ } else {
+ aapsLogger.error(
+ LTag.PUMPCOMM,
+ "from record: EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) " + "Bolus type: $bolusType not supported"
+ )
+ }
+
}
BASAL_RECORD, BASAL_RECORD_ALT -> {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index ef03a67f71..fd53d32bb0 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -98,13 +98,10 @@ class NotificationPacket(val injector: HasAndroidInjector) {
aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
var bolusType = bolusData and 0x7F
- var bolusCompleted = (bolusData shr 7) and 0x01 // TODO: Check for other flags here :)
+ val bolusCompleted: Boolean = ((bolusData shr 7) and 0x01) != 0 // TODO: Check for other flags here :)
var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() * 0.05
- // TODO Sync bolus flow:
- // If bolus is known add status
- // If bolus is not known start read bolus
- // When bolus is completed, remove bolus from medtrumPump
aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolusData: $bolusData bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
+ medtrumPump.handleBolusStatusUpdate(bolusType, bolusCompleted, bolusDelivered)
offset += 3
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 12c23b15db..8ee0910383 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -90,8 +90,8 @@ class BLEComm @Inject internal constructor(
private val mBluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
private var mBluetoothGatt: BluetoothGatt? = null
- var isConnected = false // TODO: These may be removed have no function
- var isConnecting = false// TODO: These may be removed have no function
+ private var isConnected = false // Only to track internal ble state
+ private var isConnecting = false // Only to track internal ble state
private var uartWrite: BluetoothGattCharacteristic? = null
private var uartRead: BluetoothGattCharacteristic? = null
@@ -126,14 +126,12 @@ class BLEComm @Inject internal constructor(
isConnected = false
- // TODO: Maybe replace this by (or add) a isScanning parameter?
isConnecting = true
// Find our Medtrum Device!
filters.add(
ScanFilter.Builder().setDeviceName("MT").build()
)
- // TODO Check if we need to add MAC for reconnects? Not sure if otherwise we can find the device
mBluetoothAdapter?.bluetoothLeScanner?.startScan(filters, settings, mScanCallback)
return true
}
@@ -159,6 +157,9 @@ class BLEComm @Inject internal constructor(
return false
}
+ // TODO: THIS IS A WORKAROUND TEST
+ mWritePackets = WriteCommandPackets()
+
if (mDevice != null && mDeviceSN == deviceSN) {
// Skip scanning and directly connect to gatt
aapsLogger.debug(LTag.PUMPBTCOMM, "Skipping scan and directly connecting to gatt")
@@ -178,7 +179,7 @@ class BLEComm @Inject internal constructor(
/** Connect flow: 2. When device is found this is called by onScanResult() */
@SuppressLint("MissingPermission")
@Synchronized
- fun connectGatt(device: BluetoothDevice) {
+ private fun connectGatt(device: BluetoothDevice) {
mBluetoothGatt =
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
}
@@ -196,12 +197,14 @@ class BLEComm @Inject internal constructor(
if (isConnecting) {
stopScan()
}
- mBluetoothGatt?.disconnect()
- }
-
- @Synchronized
- fun stopConnecting() {
- isConnecting = false
+ if (isConnected) {
+ mBluetoothGatt?.disconnect()
+ } else {
+ close()
+ isConnected = false
+ isConnecting = false
+ mCallback?.onBLEDisconnected()
+ }
}
@SuppressLint("MissingPermission")
@@ -347,8 +350,6 @@ class BLEComm @Inject internal constructor(
aapsLogger.debug(LTag.PUMPBTCOMM, "Notifications enabled!")
/** Connect flow: 6. Connected */
mCallback?.onBLEConnected()
- isConnected = true
- isConnecting = false
}
}
}
@@ -384,9 +385,9 @@ class BLEComm @Inject internal constructor(
private fun onConnectionStateChangeSynchronized(gatt: BluetoothGatt, status: Int, newState: Int) {
aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange newState: " + newState + " status: " + status)
if (newState == BluetoothProfile.STATE_CONNECTED) {
- handler.postDelayed({
- mBluetoothGatt?.discoverServices()
- }, WRITE_DELAY_MILLIS)
+ isConnected = true
+ isConnecting = false
+ mBluetoothGatt?.discoverServices()
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
close()
isConnected = false
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 23533c744f..8ab48a512e 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -5,6 +5,7 @@ import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.IBinder
+import android.os.SystemClock
import dagger.android.DaggerService
import dagger.android.HasAndroidInjector
import info.nightscout.core.utils.fabric.FabricPrivacy
@@ -14,6 +15,7 @@ import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.queue.Callback
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.medtrum.MedtrumPlugin
@@ -42,6 +44,7 @@ import io.reactivex.rxjava3.kotlin.plusAssign
import java.util.*
import javax.inject.Inject
import kotlin.math.abs
+import kotlin.math.round
class MedtrumService : DaggerService(), BLECommCallback {
@@ -130,12 +133,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun stopConnecting() {
- // TODO proper way for this might need send commands etc
- bleComm.stopConnecting()
+ bleComm.disconnect("stopConnecting")
}
fun disconnect(from: String) {
- // TODO proper way for this might need send commands etc
bleComm.disconnect(from)
}
@@ -155,14 +156,58 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
- fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean {
+ fun setBolus(insulin: Double, t: EventOverviewBolusProgress.Treatment): Boolean {
if (!isConnected) return false
- // TODO
- return false
+ val result = sendPacketAndGetResponse(SetBolusPacket(injector, insulin))
+
+ medtrumPump.bolusDone = false
+ medtrumPump.bolusingTreatment = t
+ medtrumPump.bolusAmountToBeDelivered = insulin
+ medtrumPump.bolusStopped = false
+ medtrumPump.bolusStopForced = false
+ medtrumPump.bolusProgressLastTimeStamp = dateUtil.now()
+
+ val bolusStart = System.currentTimeMillis()
+
+ val bolusingEvent = EventOverviewBolusProgress
+ while (medtrumPump.bolusStopped == false && result == true && medtrumPump.bolusDone == false) {
+ SystemClock.sleep(100)
+ if (System.currentTimeMillis() - medtrumPump.bolusProgressLastTimeStamp > T.secs(15).msecs()) {
+ medtrumPump.bolusStopped = true
+ medtrumPump.bolusStopForced = true
+ aapsLogger.debug(LTag.PUMPCOMM, "Communication stopped")
+ bleComm.disconnect("Communication stopped")
+ } else {
+ bolusingEvent.t = medtrumPump.bolusingTreatment
+ bolusingEvent.status = rh.gs(info.nightscout.pump.common.R.string.bolus_delivered_so_far, medtrumPump.bolusingTreatment?.insulin, medtrumPump.bolusAmountToBeDelivered)
+ bolusingEvent.percent = round((medtrumPump.bolusingTreatment?.insulin?.div(medtrumPump.bolusAmountToBeDelivered) ?: 0.0) * 100).toInt() - 1
+ rxBus.send(bolusingEvent)
+ }
+ }
+
+ bolusingEvent.t = medtrumPump.bolusingTreatment
+ bolusingEvent.percent = 99
+ medtrumPump.bolusingTreatment = null
+
+ val bolusDurationInMSec = (insulin * 60 * 1000)
+ val expectedEnd = bolusStart + bolusDurationInMSec + 2000
+ while (System.currentTimeMillis() < expectedEnd) {
+ SystemClock.sleep(1000)
+ }
+
+ // Do not call update status directly, reconnection may be needed
+ commandQueue.readStatus(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus), object : Callback() {
+ override fun run() {
+ rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus)))
+ bolusingEvent.percent = 100
+ }
+ })
+ return result
}
- fun bolusStop() {
- // TODO
+ fun stopBolus() {
+ var result = sendPacketAndGetResponse(CancelBolusPacket(injector))
+ aapsLogger.debug(LTag.PUMPCOMM, "bolusStop: result: $result")
}
fun setTempBasal(absoluteRate: Double, durationInMinutes: Int): Boolean {
@@ -190,12 +235,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun updateBasalsInPump(profile: Profile): Boolean {
- var result = false
- val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
- result = packet?.let { sendPacketAndGetResponse(it) } == true
-
- // TODO: We might want to get rid of this and cancel the TBR before we set the basal profile
+ var result = true
// Update basal affects the TBR records (the pump will cancel the TBR, set our basal profile, and resume the TBR in a new record)
+ // Cancel any TBR in progress
+ if (medtrumPump.tempBasalInProgress) {
+ result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
+ }
+ val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
+ if (result) result = packet?.let { sendPacketAndGetResponse(it) } == true
+
// Get history records, this will update the pump state and add changes in TBR to AAPS history
if (result) result = syncRecords()
@@ -211,7 +259,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
private fun syncRecords(): Boolean {
aapsLogger.debug(LTag.PUMP, "syncRecords: called!, syncedSequenceNumber: ${medtrumPump.syncedSequenceNumber}, currentSequenceNumber: ${medtrumPump.currentSequenceNumber}")
var result = false
- // TODO: Check if we need to sync older records as well
// Note: medtrum app fetches all records when they sync?
for (sequence in medtrumPump.syncedSequenceNumber..medtrumPump.currentSequenceNumber) {
result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index e1f1c74ecb..26f1a57c15 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -10,6 +10,7 @@ import info.nightscout.pump.medtrum.ui.event.UIEvent
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.rx.AapsSchedulers
@@ -17,6 +18,7 @@ import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventPumpStatusChanged
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import kotlinx.coroutines.CoroutineScope
@@ -27,6 +29,7 @@ import javax.inject.Inject
class MedtrumOverviewViewModel @Inject constructor(
private val aapsLogger: AAPSLogger,
+ private val rh: ResourceHelper,
private val rxBus: RxBus,
private val aapsSchedulers: AapsSchedulers,
private val fabricPrivacy: FabricPrivacy,
@@ -48,6 +51,10 @@ class MedtrumOverviewViewModel @Inject constructor(
val isPatchActivated: LiveData
get() = _isPatchActivated
+ private val _runningBasalRate = SingleLiveEvent()
+ val runningBasalRate: LiveData
+ get() = _runningBasalRate
+
init {
scope.launch {
medtrumPump.connectionStateFlow.collect { state ->
@@ -77,6 +84,12 @@ class MedtrumOverviewViewModel @Inject constructor(
}
}
}
+ scope.launch {
+ medtrumPump.lastBasalRateFlow.collect { rate ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel runningBasalRateFlow: $rate")
+ _runningBasalRate.postValue(String.format(rh.gs(R.string.current_basal_rate), rate))
+ }
+ }
}
override fun onCleared() {
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index 68c7073fad..c557a6cd04 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -91,6 +91,54 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index d987e70c7a..1388653576 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -12,12 +12,14 @@
synced_sequence_number
Medtrum
- MEDTRUM
+ MT
Medtrum Nano
Medtrum pump settings
BLE Status
+ Active basal
+ %.2f U/h
Start new patch
Stop patch
@@ -40,5 +42,8 @@
SN
Serial number pump base
+ Waiting for bolus end. Remaining %1$d sec.
+ Getting bolus status
+
From c2e1017d7392678b3c468dce3f2c8678b4583bae Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 25 May 2023 14:53:53 +0200
Subject: [PATCH 021/116] Moved sequence counter to BLEComm
---
.../pump/medtrum/comm/WriteCommandPackets.kt | 20 ++-----
.../pump/medtrum/services/BLEComm.kt | 50 +++++++---------
.../res/layout/fragment_medtrum_overview.xml | 2 +-
.../medtrum/comm/WriteCommandPacketsTest.kt | 60 ++-----------------
4 files changed, 31 insertions(+), 101 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
index 7a80cab3c3..1cf5a712b6 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
@@ -3,26 +3,24 @@ package info.nightscout.pump.medtrum.comm
import info.nightscout.pump.medtrum.encryption.Crypt
-class WriteCommandPackets() {
+class WriteCommandPackets(data: ByteArray, sequenceNumber: Int) {
private val CRC_8_TABLE: IntArray = intArrayOf(0, 155, 173, 54, 193, 90, 108, 247, 25, 130, 180, 47, 216, 67, 117, 238, 50, 169, 159, 4, 243, 104, 94, 197, 43, 176, 134, 29, 234, 113, 71, 220, 100, 255, 201, 82, 165, 62, 8, 147, 125, 230, 208, 75, 188, 39, 17, 138, 86, 205, 251, 96, 151, 12, 58, 161, 79, 212, 226, 121, 142, 21, 35, 184, 200, 83, 101, 254, 9, 146, 164, 63, 209, 74, 124, 231, 16, 139, 189, 38, 250, 97, 87, 204, 59, 160, 150, 13, 227, 120, 78, 213, 34, 185, 143, 20, 172, 55, 1, 154, 109, 246, 192, 91, 181, 46, 24, 131, 116, 239, 217, 66, 158, 5, 51, 168, 95, 196, 242, 105, 135, 28, 42, 177, 70, 221, 235, 112, 11, 144, 166, 61, 202, 81, 103, 252, 18, 137, 191, 36, 211, 72, 126, 229, 57, 162, 148, 15, 248, 99, 85, 206, 32, 187, 141, 22, 225, 122, 76, 215, 111, 244, 194, 89, 174, 53, 3, 152, 118, 237, 219, 64, 183, 44, 26, 129, 93, 198, 240, 107, 156, 7, 49, 170, 68, 223, 233, 114, 133, 30, 40, 179, 195, 88, 110, 245, 2, 153, 175, 52, 218, 65, 119, 236, 27, 128, 182, 45, 241, 106, 92, 199, 48, 171, 157, 6, 232, 115, 69, 222, 41, 178, 132, 31, 167, 60, 10, 145, 102, 253, 203, 80, 190, 37, 19, 136, 127, 228, 210, 73, 149, 14, 56, 163, 84, 207, 249, 98, 140, 23, 33, 186, 77, 214, 224, 123)
private val packages = mutableListOf()
private var index = 0
- private var sequenceNumber = 0
- fun setData(inputData: ByteArray) {
- resetPackets()
- // PackageIndex: 0 initially, if there are multiple packet, for the first packet it is set to 0 (not included in crc calc but sent in actual header)
+ init {
+ // PackageIndex: 0 initially, if there are multiple packets, for the first packet it is set to 0 (not included in CRC calculation but sent in actual header)
var pkgIndex = 0
var header = byteArrayOf(
- (inputData.size + 4).toByte(),
- inputData[0],
+ (data.size + 4).toByte(),
+ data[0],
sequenceNumber.toByte(),
pkgIndex.toByte()
)
- var tmp: ByteArray = header + inputData.copyOfRange(1, inputData.size)
+ var tmp: ByteArray = header + data.copyOfRange(1, data.size)
var totalCommand: ByteArray = tmp + calcCrc8(tmp, tmp.size).toByte()
if ((totalCommand.size - header.size) <= 15) {
@@ -45,7 +43,6 @@ class WriteCommandPackets() {
tmp = header + remainingCommand
packages.add(tmp + calcCrc8(tmp, tmp.size).toByte())
}
- sequenceNumber = (sequenceNumber % 255) + 1
}
fun getNextPacket(): ByteArray? {
@@ -61,11 +58,6 @@ class WriteCommandPackets() {
return !(index < packages.size)
}
- private fun resetPackets() {
- packages.clear()
- index = 0
- }
-
private fun calcCrc8(value: ByteArray, size: Int): Int {
var crc8 = 0
for (i in 0 until size) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 8ee0910383..7a70987256 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -96,7 +96,8 @@ class BLEComm @Inject internal constructor(
private var uartRead: BluetoothGattCharacteristic? = null
// Read and write buffers
- private var mWritePackets = WriteCommandPackets()
+ private var mWritePackets: WriteCommandPackets? = null
+ private var mWriteSequenceNumber: Int = 0
private var mReadPacket: ReadDataPacket? = null
private var mDeviceSN: Long = 0
@@ -157,9 +158,6 @@ class BLEComm @Inject internal constructor(
return false
}
- // TODO: THIS IS A WORKAROUND TEST
- mWritePackets = WriteCommandPackets()
-
if (mDevice != null && mDeviceSN == deviceSN) {
// Skip scanning and directly connect to gatt
aapsLogger.debug(LTag.PUMPBTCOMM, "Skipping scan and directly connecting to gatt")
@@ -180,6 +178,8 @@ class BLEComm @Inject internal constructor(
@SuppressLint("MissingPermission")
@Synchronized
private fun connectGatt(device: BluetoothDevice) {
+ // Reset sequence counter
+ mWriteSequenceNumber = 0
mBluetoothGatt =
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
}
@@ -280,10 +280,12 @@ class BLEComm @Inject internal constructor(
if (status == BluetoothGatt.GATT_SUCCESS) {
// Check if we need to finish our command!
- synchronized(mWritePackets) {
- val value: ByteArray? = mWritePackets.getNextPacket()
- if (value != null) {
- writeCharacteristic(uartWriteBTGattChar, value)
+ mWritePackets?.let {
+ synchronized(it) {
+ val value: ByteArray? = mWritePackets?.getNextPacket()
+ if (value != null) {
+ writeCharacteristic(uartWriteBTGattChar, value)
+ }
}
}
} else {
@@ -397,21 +399,21 @@ class BLEComm @Inject internal constructor(
}
}
+ @Synchronized
fun sendMessage(message: ByteArray) {
aapsLogger.debug(LTag.PUMPBTCOMM, "sendMessage message = " + Arrays.toString(message))
- if (!mWritePackets.allPacketsConsumed()) {
+ if (mWritePackets?.allPacketsConsumed() == false) {
aapsLogger.error(LTag.PUMPBTCOMM, "sendMessage not all packets consumed!! unable to sent message!")
return
}
- synchronized(mWritePackets) {
- mWritePackets.setData(message)
- val value: ByteArray? = mWritePackets.getNextPacket()
- if (value != null) {
- writeCharacteristic(uartWriteBTGattChar, value)
- } else {
- aapsLogger.error(LTag.PUMPBTCOMM, "sendMessage error in writePacket!")
- mCallback?.onSendMessageError("error in writePacket!")
- }
+ mWritePackets = WriteCommandPackets(message, mWriteSequenceNumber)
+ mWriteSequenceNumber = (mWriteSequenceNumber + 1) % 256
+ val value: ByteArray? = mWritePackets?.getNextPacket()
+ if (value != null) {
+ writeCharacteristic(uartWriteBTGattChar, value)
+ } else {
+ aapsLogger.error(LTag.PUMPBTCOMM, "sendMessage error in writePacket!")
+ mCallback?.onSendMessageError("error in writePacket!")
}
}
@@ -426,18 +428,6 @@ class BLEComm @Inject internal constructor(
return mBluetoothGatt?.getService(UUID.fromString(SERVICE_UUID))
}
- private fun getGattCharacteristic(uuid: UUID): BluetoothGattCharacteristic? {
- aapsLogger.debug(LTag.PUMPBTCOMM, "getGattCharacteristic $uuid")
- val service = getGattService()
- if (mBluetoothAdapter == null || mBluetoothGatt == null || service == null) {
- aapsLogger.error("BluetoothAdapter not initialized_ERROR")
- isConnecting = false
- isConnected = false
- return null
- }
- return service.getCharacteristic(uuid)
- }
-
@Suppress("DEPRECATION")
@SuppressLint("MissingPermission")
@Synchronized
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index c557a6cd04..cc629b9ff1 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -123,7 +123,7 @@
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
- android:text="@string/colon"
+ android:text=":"
android:textSize="16sp" />
Date: Thu, 25 May 2023 20:14:51 +0200
Subject: [PATCH 022/116] Added some stuff to the overview
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 35 +++++-
.../pump/medtrum/services/MedtrumService.kt | 2 +-
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 30 +++++
.../res/layout/fragment_medtrum_overview.xml | 117 ++++++++++++++++++
pump/medtrum/src/main/res/values/strings.xml | 6 +-
5 files changed, 182 insertions(+), 8 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 0feda438df..0c8822c192 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -75,6 +75,14 @@ class MedtrumPump @Inject constructor(
set(value) {
_lastBasalRate.value = value
}
+
+ private val _reservoir = MutableStateFlow(0.0)
+ val reservoirFlow: StateFlow = _reservoir
+ var reservoir: Double
+ get() = _reservoir.value
+ set(value) {
+ _reservoir.value = value
+ }
/** Stuff stored in SP */
private var _patchSessionToken = 0L
@@ -118,12 +126,13 @@ class MedtrumPump @Inject constructor(
sp.putString(R.string.key_actual_basal_profile, encodedString)
}
- private var _lastBasalType: BasalType = BasalType.NONE
+ private var _lastBasalType: MutableStateFlow = MutableStateFlow(BasalType.NONE)
+ val lastBasalTypeFlow: StateFlow = _lastBasalType
var lastBasalType: BasalType
- get() = _lastBasalType
+ get() = _lastBasalType.value
set(value) {
- _lastBasalType = value
- sp.putInt(R.string.key_last_basal_type, value.ordinal)
+ _lastBasalType.value = value
+ sp.putInt(R.string.key_last_basal_type, value.ordinal) // TODO is this still needed in SP?
}
private var _pumpSN = 0L
@@ -137,7 +146,6 @@ class MedtrumPump @Inject constructor(
var patchStartTime = 0L // Time in seconds!
var patchAge = 0L // Time in seconds!
- var reservoir = 0.0
var batteryVoltage_A = 0.0
var batteryVoltage_B = 0.0
@@ -187,7 +195,7 @@ class MedtrumPump @Inject constructor(
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
_patchId = sp.getLong(R.string.key_patch_id, 0L)
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
- _lastBasalType = enumValues()[sp.getInt(R.string.key_last_basal_type, 0)]
+ lastBasalType = enumValues()[sp.getInt(R.string.key_last_basal_type, 0)] // TODO: is this nice?
val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
try {
@@ -339,6 +347,21 @@ class MedtrumPump @Inject constructor(
LTag.PUMPCOMM,
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime)"
)
+ } else if (basalType == BasalType.NONE && expectedTemporaryBasal?.pumpId != basalStartTime) { // Also some sort of suspend or unkown by pump
+ val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
+ timestamp = basalStartTime,
+ rate = basalRate,
+ duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER
+ isAbsolute = true,
+ type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
+ pumpId = basalStartTime,
+ pumpType = pumpType,
+ pumpSerial = pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime)"
+ )
}
// Update medtrum pump state
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 8ab48a512e..907cbeadec 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -191,7 +191,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
val bolusDurationInMSec = (insulin * 60 * 1000)
val expectedEnd = bolusStart + bolusDurationInMSec + 2000
- while (System.currentTimeMillis() < expectedEnd) {
+ while (System.currentTimeMillis() < expectedEnd && result == true) {
SystemClock.sleep(1000)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index 26f1a57c15..51eb6503d9 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -51,10 +51,22 @@ class MedtrumOverviewViewModel @Inject constructor(
val isPatchActivated: LiveData
get() = _isPatchActivated
+ private val _pumpState = SingleLiveEvent()
+ val pumpState: LiveData
+ get() = _pumpState
+
+ private val _basalType = SingleLiveEvent()
+ val basalType: LiveData
+ get() = _basalType
+
private val _runningBasalRate = SingleLiveEvent()
val runningBasalRate: LiveData
get() = _runningBasalRate
+ private val _reservoir = SingleLiveEvent()
+ val reservoir: LiveData
+ get() = _reservoir
+
init {
scope.launch {
medtrumPump.connectionStateFlow.collect { state ->
@@ -90,6 +102,24 @@ class MedtrumOverviewViewModel @Inject constructor(
_runningBasalRate.postValue(String.format(rh.gs(R.string.current_basal_rate), rate))
}
}
+ scope.launch {
+ medtrumPump.pumpStateFlow.collect { state ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
+ _pumpState.postValue(state.toString())
+ }
+ }
+ scope.launch {
+ medtrumPump.reservoirFlow.collect { reservoir ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel reservoirFlow: $reservoir")
+ _reservoir.postValue(String.format(rh.gs(R.string.reservoir_level), reservoir))
+ }
+ }
+ scope.launch {
+ medtrumPump.lastBasalTypeFlow.collect { basalType ->
+ aapsLogger.debug(LTag.PUMP, "MedtrumViewModel basalTypeFlow: $basalType")
+ _basalType.postValue(basalType.toString())
+ }
+ }
}
override fun onCleared() {
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index cc629b9ff1..398c351044 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -100,6 +100,84 @@
android:layout_marginBottom="5dp"
android:background="@color/list_delimiter" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 1388653576..ef2b5de75e 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -18,7 +18,11 @@
BLE Status
- Active basal
+ Pump state
+ Reservoir
+ %.2f U
+ Basal type
+ Basal rate
%.2f U/h
Start new patch
Stop patch
From d8427c6d566fd9d001e2bbe1171be358985b625a Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 28 May 2023 10:27:13 +0200
Subject: [PATCH 023/116] Rescan when connection is lost during connecting
---
.../info/nightscout/pump/medtrum/services/BLEComm.kt | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 7a70987256..3ff7d00acb 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -195,14 +195,15 @@ class BLEComm @Inject internal constructor(
}
aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
if (isConnecting) {
+ isConnecting = false
stopScan()
- }
+ SystemClock.sleep(100)
+ }
if (isConnected) {
mBluetoothGatt?.disconnect()
} else {
close()
isConnected = false
- isConnecting = false
mCallback?.onBLEDisconnected()
}
}
@@ -391,6 +392,13 @@ class BLEComm @Inject internal constructor(
isConnecting = false
mBluetoothGatt?.discoverServices()
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+ if (isConnecting) {
+ // When we are disconnected during connecting, we reset the device address to force a new scan
+ aapsLogger.warn(LTag.PUMPBTCOMM, "Disconnected while connecting! Reset device address")
+ mDevice = null
+ // Wait a bit before retrying
+ SystemClock.sleep(2000)
+ }
close()
isConnected = false
isConnecting = false
From 37a6a4f271538eeff9b43a7d0748065f97fcc6d6 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 28 May 2023 19:50:00 +0200
Subject: [PATCH 024/116] Update unit tests, cleanup
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 11 ++--
.../pump/medtrum/comm/WriteCommandPackets.kt | 3 -
.../medtrum/comm/packets/ActivatePacket.kt | 1 -
.../medtrum/comm/packets/AuthorizePacket.kt | 2 -
.../comm/packets/CancelTempBasalPacket.kt | 1 -
.../medtrum/comm/packets/GetRecordPacket.kt | 1 -
.../comm/packets/NotificationPacket.kt | 6 +-
.../comm/packets/ReadBolusStatePacket.kt | 4 +-
.../comm/packets/SetBasalProfilePacket.kt | 2 -
.../comm/packets/SetBolusMotorPacket.kt | 3 +-
.../comm/packets/SetTempBasalPacket.kt | 5 --
.../medtrum/comm/packets/SynchronizePacket.kt | 1 -
.../pump/medtrum/MedtrumPumpTest.kt | 39 ++++++++++++
.../comm/packets/ActivatePacketTest.kt | 9 +--
.../comm/packets/CancelTempBasalPacketTest.kt | 7 ++-
.../comm/packets/GetRecordPacketTest.kt | 24 ++++++--
.../comm/packets/NotificationPacketTest.kt | 59 ++++++++++++++++++-
.../comm/packets/SetBasalProfilePacketTest.kt | 7 ++-
.../comm/packets/SetTempBasalPacketTest.kt | 7 ++-
.../comm/packets/StopPatchPacketTest.kt | 2 +-
.../comm/packets/SynchronizePacketTest.kt | 27 +++++++++
21 files changed, 171 insertions(+), 50 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 0c8822c192..086d54be39 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -1,7 +1,6 @@
package info.nightscout.pump.medtrum
import android.util.Base64
-import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.TemporaryBasalStorage
@@ -123,7 +122,7 @@ class MedtrumPump @Inject constructor(
set(value) {
_actualBasalProfile = value
val encodedString = Base64.encodeToString(value, Base64.DEFAULT)
- sp.putString(R.string.key_actual_basal_profile, encodedString)
+ sp.putString(R.string.key_actual_basal_profile, encodedString?: "")
}
private var _lastBasalType: MutableStateFlow = MutableStateFlow(BasalType.NONE)
@@ -311,7 +310,7 @@ class MedtrumPump @Inject constructor(
LTag.PUMP,
"handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + "receivedTime: $receivedTime"
)
- val expectedTemporaryBasal = pumpSync.expectedPumpState().temporaryBasal
+ val expectedTemporaryBasal = pumpSync.expectedPumpState()?.temporaryBasal
if (basalType.isTempBasal() && expectedTemporaryBasal?.pumpId != basalStartTime) {
// Note: temporaryBasalInfo will be removed from temporaryBasalStorage after this call
val temporaryBasalInfo = temporaryBasalStorage.findTemporaryBasal(basalStartTime, basalRate)
@@ -330,7 +329,7 @@ class MedtrumPump @Inject constructor(
)
aapsLogger.debug(
LTag.PUMPCOMM,
- "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " + "Rate: $basalRate Duration: ${duration}"
+ "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " + "Rate: $basalRate Duration: ${duration} temporaryBasalInfo: $temporaryBasalInfo, expectedTemporaryBasal: $expectedTemporaryBasal"
)
} else if (basalType.isSuspendedByPump() && expectedTemporaryBasal?.pumpId != basalStartTime) {
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
@@ -345,7 +344,7 @@ class MedtrumPump @Inject constructor(
)
aapsLogger.debug(
LTag.PUMPCOMM,
- "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime)"
+ "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) expectedTemporaryBasal: $expectedTemporaryBasal"
)
} else if (basalType == BasalType.NONE && expectedTemporaryBasal?.pumpId != basalStartTime) { // Also some sort of suspend or unkown by pump
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
@@ -360,7 +359,7 @@ class MedtrumPump @Inject constructor(
)
aapsLogger.debug(
LTag.PUMPCOMM,
- "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime)"
+ "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) expectedTemporaryBasal: $expectedTemporaryBasal"
)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
index 1cf5a712b6..ae0f18e9f4 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/WriteCommandPackets.kt
@@ -1,8 +1,5 @@
package info.nightscout.pump.medtrum.comm
-import info.nightscout.pump.medtrum.encryption.Crypt
-
-
class WriteCommandPackets(data: ByteArray, sequenceNumber: Int) {
private val CRC_8_TABLE: IntArray = intArrayOf(0, 155, 173, 54, 193, 90, 108, 247, 25, 130, 180, 47, 216, 67, 117, 238, 50, 169, 159, 4, 243, 104, 94, 197, 43, 176, 134, 29, 234, 113, 71, 220, 100, 255, 201, 82, 165, 62, 8, 147, 125, 230, 208, 75, 188, 39, 17, 138, 86, 205, 251, 96, 151, 12, 58, 161, 79, 212, 226, 121, 142, 21, 35, 184, 200, 83, 101, 254, 9, 146, 164, 63, 209, 74, 124, 231, 16, 139, 189, 38, 250, 97, 87, 204, 59, 160, 150, 13, 227, 120, 78, 213, 34, 185, 143, 20, 172, 55, 1, 154, 109, 246, 192, 91, 181, 46, 24, 131, 116, 239, 217, 66, 158, 5, 51, 168, 95, 196, 242, 105, 135, 28, 42, 177, 70, 221, 235, 112, 11, 144, 166, 61, 202, 81, 103, 252, 18, 137, 191, 36, 211, 72, 126, 229, 57, 162, 148, 15, 248, 99, 85, 206, 32, 187, 141, 22, 225, 122, 76, 215, 111, 244, 194, 89, 174, 53, 3, 152, 118, 237, 219, 64, 183, 44, 26, 129, 93, 198, 240, 107, 156, 7, 49, 170, 68, 223, 233, 114, 133, 30, 40, 179, 195, 88, 110, 245, 2, 153, 175, 52, 218, 65, 119, 236, 27, 128, 182, 45, 241, 106, 92, 199, 48, 171, 157, 6, 232, 115, 69, 222, 41, 178, 132, 31, 167, 60, 10, 145, 102, 253, 203, 80, 190, 37, 19, 136, 127, 228, 210, 73, 149, 14, 56, 163, 84, 207, 249, 98, 140, 23, 33, 186, 77, 214, 224, 123)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
index 627c7f2344..f18998d186 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
@@ -99,7 +99,6 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
medtrumPump.syncedSequenceNumber = basalSequence // We are activated, reset the synced seq nr ()
// Update the actual basal profile
medtrumPump.actualBasalProfile = basalProfile
- // TODO: Handle history entry
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
// Update the pump in the database, technically this is not a new pump only new patch, but still TBR's etc need to be cannceled
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
index 2093ae8cf7..4cf10a580c 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
@@ -2,12 +2,10 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
-import info.nightscout.pump.medtrum.comm.enums.CommandType
import info.nightscout.pump.medtrum.comm.enums.CommandType.AUTH_REQ
import info.nightscout.pump.medtrum.encryption.Crypt
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
-import info.nightscout.rx.logging.LTag
import javax.inject.Inject
class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
index d5ca93c993..b6bb78c399 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
@@ -7,7 +7,6 @@ import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
-import info.nightscout.rx.logging.LTag
import javax.inject.Inject
class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
index 78eabeca96..600f2223cf 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -14,7 +14,6 @@ import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.utils.DateUtil
-import info.nightscout.shared.utils.T
import javax.inject.Inject
class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int) : MedtrumPacket(injector) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index fd53d32bb0..6c9695f624 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -4,14 +4,12 @@ import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
-import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import javax.inject.Inject
-import kotlin.experimental.and
class NotificationPacket(val injector: HasAndroidInjector) {
@@ -107,7 +105,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_EXTENDED_BOLUS != 0) {
aapsLogger.error(LTag.PUMPCOMM, "Extended bolus notification received, extended bolus not supported!")
- // TODO Handle error and stop pump if this happens
+ // TODO Handle error and stop pump if this happens?
offset += 3
}
@@ -144,7 +142,6 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_LIFE_TIME != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Life time notification received")
- // TODO Check if timezone offset needs to be added
medtrumPump.patchAge = data.copyOfRange(offset, offset + 4).toLong()
aapsLogger.debug(LTag.PUMPCOMM, "Patch age: ${medtrumPump.patchAge}")
offset += 4
@@ -162,7 +159,6 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_STORAGE != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Storage notification received")
- // TODO, trigger check for new sequence?
val sequence = data.copyOfRange(offset, offset + 2).toInt()
if (sequence > medtrumPump.currentSequenceNumber) {
medtrumPump.currentSequenceNumber = sequence
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
index 222fd55181..4672b1d185 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ReadBolusStatePacket.kt
@@ -4,6 +4,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.comm.enums.CommandType.READ_BOLUS_STATE
class ReadBolusStatePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+ // UNUSED
+ // Bolus sync is currently done by getting the records and syncing then with AAPS pumpSync there
var bolusData: ByteArray = byteArrayOf()
@@ -20,7 +22,7 @@ class ReadBolusStatePacket(injector: HasAndroidInjector) : MedtrumPacket(injecto
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- // TODO: Handle bolus data here
+ // UNUSED
bolusData = data.copyOfRange(RESP_BOLUS_DATA_START, data.size)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
index 8d7a400ea5..88684d2096 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacket.kt
@@ -50,8 +50,6 @@ class SetBasalProfilePacket(injector: HasAndroidInjector, private val basalProfi
// Update the actual basal profile
medtrumPump.actualBasalProfile = basalProfile
- // TODO: Do we need to let AAPS know? Maybe depends on where we cancel TBR if we need to
- // TODO: Handle history entry
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime)
}
return success
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
index 25603ab982..c41d5fa1a9 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetBolusMotorPacket.kt
@@ -5,12 +5,13 @@ import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BOLUS_MOTOR
class SetBolusMotorPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+ // UNUSED in our driver
+
init {
opCode = SET_BOLUS_MOTOR.code
}
override fun getRequest(): ByteArray {
- // TODO CHECK! Seems to be a feature? to set the bolus to vibrate? TEST!
return byteArrayOf(opCode) + 0.toByte()
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
index f203f21a4d..8e392d2ded 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacket.kt
@@ -60,11 +60,6 @@ class SetTempBasalPacket(injector: HasAndroidInjector, private val absoluteRate:
val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
aapsLogger.debug(LTag.PUMPCOMM, "Basal status update: type=$basalType, rate=$basalRate, sequence=$basalSequence, patchId=$basalPatchId, startTime=$basalStartTime, rawTime=$rawTime")
- // TODO: For debugging remove later
- val pumpTime = MedtrumTimeUtil().getCurrentTimePumpSeconds()
- val systemTime = System.currentTimeMillis()
- aapsLogger.debug(LTag.PUMPCOMM, "Pump time: $pumpTime, System time: $systemTime")
-
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
}
return success
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
index 5f649e22cd..19ff644a91 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
@@ -6,7 +6,6 @@ import info.nightscout.pump.medtrum.comm.enums.CommandType.SYNCHRONIZE
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
-import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import javax.inject.Inject
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
index 0c3a361a2b..5dbfe34f78 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
@@ -2,9 +2,14 @@ package info.nightscout.pump.medtrum
import info.nightscout.core.extensions.pureProfileFromJson
import info.nightscout.core.profile.ProfileSealed
+import info.nightscout.shared.utils.DateUtil
import org.json.JSONObject
import org.junit.jupiter.api.Test
import org.junit.Assert.*
+import org.mockito.Mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.any
class MedtrumPumpTest : MedtrumTestBase() {
@@ -49,4 +54,38 @@ class MedtrumPumpTest : MedtrumTestBase() {
// Expected values
assertNull(result)
}
+
+ @Test fun getCurrentHourlyBasalFromMedtrumProfileArrayGivenProfileWhenValuesSetThenReturnCorrectValue() {
+ // Inputs
+ // Basal profile with 7 elements:
+ // 00:00 : 2.1
+ // 04:00 : 1.9
+ // 06:00 : 1.7
+ // 08:00 : 1.5
+ // 16:00 : 1.6
+ // 21:00 : 1.7
+ // 23:00 : 2
+ val profileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\"," +
+ "\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"},{\"time\":\"02:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\"," +
+ "\"basal\":[{\"time\":\"00:00\",\"value\":\"2.1\"},{\"time\":\"04:00\",\"value\":\"1.9\"},{\"time\":\"06:00\",\"value\":\"1.7\"}," +
+ "{\"time\":\"08:00\",\"value\":\"1.5\"},{\"time\":\"16:00\",\"value\":\"1.6\"},{\"time\":\"21:00\",\"value\":\"1.7\"},{\"time\":\"23:00\",\"value\":\"2\"}]," +
+ "\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
+ val profile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(profileJSON), dateUtil)!!)
+ val profileArray = medtrumPump.buildMedtrumProfileArray(profile)
+
+ // For 03:59
+ `when`(dateUtil.dateAndTimeString((any()))).thenReturn("2023-01-01T03:59:00.000Z")
+ val result = medtrumPump.getCurrentHourlyBasalFromMedtrumProfileArray(profileArray!!)
+ assertEquals(2.1, result, 0.01)
+
+ // For 23:59
+ `when`(dateUtil.dateAndTimeString((any()))).thenReturn("2023-01-01T23:59:59.999Z")
+ val result1 = medtrumPump.getCurrentHourlyBasalFromMedtrumProfileArray(profileArray!!)
+ assertEquals(2.0, result1, 0.01)
+
+ // For 00:00
+ `when`(dateUtil.dateAndTimeString((any()))).thenReturn("2023-01-01T00:00:00.000Z")
+ val result2 = medtrumPump.getCurrentHourlyBasalFromMedtrumProfileArray(profileArray!!)
+ assertEquals(2.1, result2, 0.01)
+ }
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
index 609e47ca87..7a29b2e516 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
@@ -4,6 +4,7 @@ import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -56,12 +57,12 @@ class ActivatePacketTest : MedtrumTestBase() {
// Expected values
val expectedPatchId = 41L
- val expectedTime = 1675605528L
- val exptectedBasalType = 1
+ val expectedTime = 1675605528000L
+ val exptectedBasalType = BasalType.STANDARD
val expectedBasalRate = 1.5
val expectedBasalSequence = 1
- val expectedBasalPatchId = 41
- val expectedBasalStart = 1675605528L
+ val expectedBasalPatchId = 41L
+ val expectedBasalStart = 1675605528000L
assertEquals(true, result)
assertEquals(expectedPatchId, medtrumPump.patchId)
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
index 1f08aa0e45..f5d034b212 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
@@ -3,6 +3,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -41,11 +42,11 @@ class CancelTempBasalPacketTest : MedtrumTestBase() {
val result = packet.handleResponse(repsonse)
// Expected values
- val expectedBasalType = 1
+ val expectedBasalType = BasalType.STANDARD
val expectedBasalRate = 1.1
val expectedBasalSequence = 3
- val expectedStartTime = 1679575392L
- val expectedPatchId = 146
+ val expectedStartTime = 1679575392000L
+ val expectedPatchId = 146L
assertTrue(result)
assertEquals(expectedBasalType, medtrumPump.lastBasalType)
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacketTest.kt
index 2816996dad..a08f97e3d4 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacketTest.kt
@@ -35,12 +35,28 @@ class GetRecordPacketTest : MedtrumTestBase() {
}
@Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
- assertTrue(false)
- // TODO: Implement history and test
+ // Inputs
+ val data = byteArrayOf(35, 99, 9, 1, 0, 0, -86, 28, 2, -1, -5, -40, -27, -18, 14, 0, -64, 1, -91, -20, -82, 17, -91, -20, -82, 17, 1, 0, 26, 0, 0, 0, -102, 0, -48)
+
+ // Call
+ val packet = GetRecordPacket(packetInjector, 0)
+ val result = packet.handleResponse(data)
+
+ // Expected values
+ assertEquals(true, result)
+ assertEquals(false, packet.failed)
}
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
- assertTrue(false)
- // TODO: Implement history and test
+ // Inputs
+ val data = byteArrayOf(35, 99, 9, 1, 0, 0, -86, 28, 2, -1, -5, -40, -27, -18, 14, 0, -64)
+
+ // Call
+ val packet = GetRecordPacket(packetInjector, 0)
+ val result = packet.handleResponse(data)
+
+ // Expected values
+ assertEquals(false, result)
+ assertEquals(true, packet.failed)
}
}
\ No newline at end of file
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacketTest.kt
index 8019981ebb..7316743155 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacketTest.kt
@@ -3,8 +3,10 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
+import info.nightscout.rx.events.EventOverviewBolusProgress
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -32,8 +34,59 @@ class NotificationPacketTest : MedtrumTestBase() {
assertEquals(medtrumPump.pumpState, MedtrumPumpState.fromByte(state))
}
- @Test fun handleMaskedMessageGivenMaskAndDataThenDataSaved() {
- // TODO: Implement
- assertTrue(false)
+ @Test fun handleNotificationGivenBasalDataThenDataSaved() {
+ // Inputs
+ val data = byteArrayOf(32, 40, 64, 6, 25, 0, 14, 0, 84, -93, -83, 17, 17, 64, 0, -104, 14, 0, 16)
+
+ // Call
+ NotificationPacket(packetInjector).handleNotification(data)
+
+ // Expected values
+ assertEquals(BasalType.ABSOLUTE_TEMP, medtrumPump.lastBasalType)
+ assertEquals(0.85, medtrumPump.lastBasalRate, 0.01)
+ assertEquals(25, medtrumPump.lastBasalSequence)
+ assertEquals(14, medtrumPump.lastBasalPatchId)
+ assertEquals(1685126612000, medtrumPump.lastBasalStartTime)
+ assertEquals(186.80, medtrumPump.reservoir, 0.01)
+ }
+
+ @Test fun handleNotificationGivenSequenceAndOtherDataThenDataSaved() {
+ // Inputs
+ val data = byteArrayOf(32, 0, 17, -89, 0, 14, 0, 0, 0, 0, 0, 0)
+
+ // Call
+ NotificationPacket(packetInjector).handleNotification(data)
+
+ // Expected values
+ assertEquals(167, medtrumPump.currentSequenceNumber)
+ // TODO: Test error notif on wrong patch id
+ }
+
+ @Test fun handleNotificationGivenBolusInProgressThenDataSaved() {
+ // Inputs
+ val data = byteArrayOf(32, 34, 16, 0, 3, 0, -58, 12, 0, 0, 0, 0, 0)
+ medtrumPump.bolusingTreatment = EventOverviewBolusProgress.Treatment(0.0, 0, false, 1)
+
+ // Call
+ NotificationPacket(packetInjector).handleNotification(data)
+
+ // Expected values
+ assertEquals(false, medtrumPump.bolusDone)
+ assertEquals(0.15, medtrumPump.bolusingTreatment!!.insulin, 0.01)
+ assertEquals(163.5, medtrumPump.reservoir, 0.01)
+ }
+
+ @Test fun handleNotificationGivenBolusFinnishedThenDataSaved() {
+ // Inputs
+ val data = byteArrayOf(32, 34, 17, -128, 33, 0, -89, 12, -80, 0, 14, 0, 0, 0, 0, 0, 0)
+ medtrumPump.bolusingTreatment = EventOverviewBolusProgress.Treatment(0.0, 0, false, 1)
+
+ // Call
+ NotificationPacket(packetInjector).handleNotification(data)
+
+ // Expected values
+ assertEquals(true, medtrumPump.bolusDone)
+ assertEquals(1.65, medtrumPump.bolusingTreatment!!.insulin, 0.01)
+ assertEquals(161.95, medtrumPump.reservoir, 0.01)
}
}
\ No newline at end of file
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
index 64165f3bd2..f1919fff32 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetBasalProfilePacketTest.kt
@@ -3,6 +3,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -43,11 +44,11 @@ class SetBasalProfilePacketTest : MedtrumTestBase() {
val result = packet.handleResponse(repsonse)
// Expected values
- val expectedBasalType = 1
+ val expectedBasalType = BasalType.STANDARD
val expectedBasalRate = 1.1
val expectedBasalSequence = 3
- val expectedStartTime = 1679575392L
- val expectedPatchId = 146
+ val expectedStartTime = 1679575392000L
+ val expectedPatchId = 146L
assertTrue(result)
assertEquals(expectedBasalType, medtrumPump.lastBasalType)
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
index ac125c3b69..8220cd7b0d 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetTempBasalPacketTest.kt
@@ -3,6 +3,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.comm.enums.BasalType
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -45,11 +46,11 @@ class SetTempBasalPacketTest : MedtrumTestBase() {
val result = packet.handleResponse(response)
// Expected values
- val expectedBasalType = 6
+ val expectedBasalType = BasalType.ABSOLUTE_TEMP
val expectedBasalRate = 1.25
val expectedBasalSequence = 2
- val expectedStartTime = 1679575112L
- val expectedPatchId = 146
+ val expectedStartTime = 1679575112000L
+ val expectedPatchId = 146L
assertTrue(result)
assertEquals(expectedBasalType, medtrumPump.lastBasalType)
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
index f626a2af3f..ec8c78b597 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/StopPatchPacketTest.kt
@@ -41,7 +41,7 @@ class StopPatchPacketTest : MedtrumTestBase() {
val result = packet.handleResponse(response)
// Expected values
- val expectedPatchId = 146
+ val expectedPatchId = 146L
val expectedStopSequence = 23
assertEquals(expectedPatchId, medtrumPump.lastStopPatchId)
assertEquals(expectedStopSequence, medtrumPump.lastStopSequence)
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
index 2250202bf1..3d9913aea8 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacketTest.kt
@@ -2,7 +2,10 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
+import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.comm.enums.BasalType
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
import org.junit.jupiter.api.Test
import org.junit.Assert.*
@@ -73,4 +76,28 @@ class SynchronizePacketTest : MedtrumTestBase() {
assertEquals(false, result)
assertEquals(true, packet.failed)
}
+
+ @Test fun handleResponseContainingSyncDataThenDataSaved() {
+ // Inputs
+ val data = byteArrayOf(47, 3, 3, 1, 0, 0, 32, -18, 13, -128, 5, 0, -128, 0, 0, 6, 25, 0, 14, 0, 84, -93, -83, 17, 17, 64, 0, -104, 14, -8, -119, -83, 17, -16, 11, 90, 26, 0, 14, 0, -69, 31, 0, 0, -116, 14, -56)
+
+ // Call
+ val packet = SynchronizePacket(packetInjector)
+ val result = packet.handleResponse(data)
+
+ // Expected values
+ assertEquals(true, result)
+ assertEquals(false, packet.failed)
+ assertEquals(MedtrumPumpState.ACTIVE, packet.medtrumPump.pumpState)
+ assertEquals(BasalType.ABSOLUTE_TEMP, packet.medtrumPump.lastBasalType)
+ assertEquals(0.85, packet.medtrumPump.lastBasalRate, 0.01)
+ assertEquals(25, packet.medtrumPump.lastBasalSequence)
+ assertEquals(14, packet.medtrumPump.lastBasalPatchId)
+ assertEquals(1685126612000, packet.medtrumPump.lastBasalStartTime)
+ assertEquals(186.80, packet.medtrumPump.reservoir, 0.01)
+ assertEquals(296585720, packet.medtrumPump.patchAge)
+ assertEquals(5.96875, packet.medtrumPump.batteryVoltage_A, 0.01)
+ assertEquals(2.8125, packet.medtrumPump.batteryVoltage_B, 0.01)
+ assertEquals(1388542523000, packet.medtrumPump.patchStartTime)
+ }
}
From 3c8faa6723ac0af3dcc3c429ce682a99e85289fb Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Mon, 29 May 2023 14:40:08 +0200
Subject: [PATCH 025/116] Use timeout in connect states, other minor changes
---
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 14 +-
.../nightscout/pump/medtrum/MedtrumPump.kt | 22 +--
.../pump/medtrum/services/MedtrumService.kt | 159 +++++++++++-------
pump/medtrum/src/main/res/values/strings.xml | 1 -
4 files changed, 110 insertions(+), 86 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 6b7fe84598..2d154856c5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -236,8 +236,8 @@ import kotlin.math.round
result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep
result.bolusDelivered = t.insulin
if (!result.success) {
- // Todo error code?
- result.comment = "error"
+ // Note: There are no error codes
+ result.comment = "failed"
} else {
result.comment = "ok"
}
@@ -266,8 +266,8 @@ import kotlin.math.round
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute - absoluteRate: $absoluteRate, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
- // round rate to 0.05
- val pumpRate = round(absoluteRate * 20) / 20 // TODO: Maybe replace by constraints thing
+ // round rate to pump rate
+ val pumpRate = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value()
temporaryBasalStorage.add(PumpSync.PumpState.TemporaryBasal(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), pumpRate, true, tbrType, 0L, 0L))
val connectionOk = medtrumService?.setTempBasal(pumpRate, durationInMinutes) ?: false
if (connectionOk
@@ -307,7 +307,7 @@ import kotlin.math.round
}
override fun cancelExtendedBolus(): PumpEnactResult {
- return PumpEnactResult(injector) // TODO
+ return PumpEnactResult(injector)
}
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
@@ -333,10 +333,10 @@ import kotlin.math.round
return ""// TODO
}
- override val isFakingTempsByExtendedBoluses: Boolean = false //TODO
+ override val isFakingTempsByExtendedBoluses: Boolean = false
override fun loadTDDs(): PumpEnactResult {
- return PumpEnactResult(injector) // TODO
+ return PumpEnactResult(injector) // Note: Can implement this if we implement history fully (no priority)
}
override fun canHandleDST(): Boolean {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 086d54be39..330bbdaaef 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -66,7 +66,15 @@ class MedtrumPump @Inject constructor(
set(value) {
_primeProgress.value = value
}
-
+
+ private var _lastBasalType: MutableStateFlow = MutableStateFlow(BasalType.NONE)
+ val lastBasalTypeFlow: StateFlow = _lastBasalType
+ var lastBasalType: BasalType
+ get() = _lastBasalType.value
+ set(value) {
+ _lastBasalType.value = value
+ }
+
private val _lastBasalRate = MutableStateFlow(0.0)
val lastBasalRateFlow: StateFlow = _lastBasalRate
var lastBasalRate: Double
@@ -125,15 +133,6 @@ class MedtrumPump @Inject constructor(
sp.putString(R.string.key_actual_basal_profile, encodedString?: "")
}
- private var _lastBasalType: MutableStateFlow = MutableStateFlow(BasalType.NONE)
- val lastBasalTypeFlow: StateFlow = _lastBasalType
- var lastBasalType: BasalType
- get() = _lastBasalType.value
- set(value) {
- _lastBasalType.value = value
- sp.putInt(R.string.key_last_basal_type, value.ordinal) // TODO is this still needed in SP?
- }
-
private var _pumpSN = 0L
val pumpSN: Long
get() = _pumpSN
@@ -161,8 +160,6 @@ class MedtrumPump @Inject constructor(
var bolusDone = false // success end
// Last basal status update
- // TODO: Save this in SP?
-
var lastBasalSequence = 0
var lastBasalPatchId = 0L
var lastBasalStartTime = 0L
@@ -194,7 +191,6 @@ class MedtrumPump @Inject constructor(
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
_patchId = sp.getLong(R.string.key_patch_id, 0L)
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
- lastBasalType = enumValues()[sp.getInt(R.string.key_last_basal_type, 0)] // TODO: is this nice?
val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
try {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 907cbeadec..91facb8a59 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -41,6 +41,11 @@ import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
import java.util.*
import javax.inject.Inject
import kotlin.math.abs
@@ -74,6 +79,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
private var currentState: State = IdleState()
private var mPacket: MedtrumPacket? = null
+
+ private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
val isConnected: Boolean
get() = medtrumPump.connectionState == ConnectionState.CONNECTED
@@ -100,8 +107,9 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
override fun onDestroy() {
- disposable.clear()
super.onDestroy()
+ disposable.clear()
+ scope.cancel()
}
fun connect(from: String): Boolean {
@@ -141,12 +149,9 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun readPumpStatus() {
- // TODO decide what we need to do here
- var result = false
-
// Most of these things are already done when a connection is setup, but wo dont know how long the pump was connected for?
// So just do a syncronize to make sure we have the latest data
- result = sendPacketAndGetResponse(SynchronizePacket(injector))
+ var result = sendPacketAndGetResponse(SynchronizePacket(injector))
// Sync records (based on the info we have from the sync)
if (result) result = syncRecords()
@@ -224,9 +229,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun cancelTempBasal(): Boolean {
- var result = false
-
- result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
+ var result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
// Get history records, this will update the pump state
if (result) result = syncRecords()
@@ -330,6 +333,9 @@ class MedtrumService : DaggerService(), BLECommCallback {
// State class, Can we move this to different file?
private abstract inner class State {
+ protected var responseHandled = false
+ protected var responseSuccess = false
+
open fun onEnter() {}
open fun onIndication(data: ByteArray) {
aapsLogger.debug(LTag.PUMPCOMM, "onIndication: " + this.toString() + "Should not be called here!")
@@ -339,22 +345,39 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.debug(LTag.PUMPCOMM, "onConnected")
}
- open fun onDisconnected() {
+ fun onDisconnected() {
aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected")
medtrumPump.connectionState = ConnectionState.DISCONNECTED
if (medtrumPump.patchActivated) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
}
- // TODO: Check flow for this
+ responseHandled = true
+ responseSuccess = false
toState(IdleState())
}
- open fun waitForResponse(): Boolean {
- return false
+ fun waitForResponse(): Boolean {
+ val startTime = System.currentTimeMillis()
+ val timeoutMillis = T.secs(45).msecs()
+ while (!responseHandled) {
+ if (System.currentTimeMillis() - startTime > timeoutMillis) {
+ // If we haven't received a response in the specified time, assume the command failed
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service State timeout")
+ // Disconnect to cancel any outstanding commands and go back to ready state
+ bleComm.disconnect("Timeout")
+ toState(IdleState())
+ return false
+ }
+ SystemClock.sleep(100)
+ }
+ aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service State responseHandled: $responseHandled responseSuccess: $responseSuccess")
+ return responseSuccess
}
- open fun onSendMessageError(reason: String) {
+ fun onSendMessageError(reason: String) {
aapsLogger.debug(LTag.PUMPCOMM, "onSendMessageError: " + this.toString() + "reason: $reason")
+ responseHandled = true
+ responseSuccess = false
}
}
@@ -368,13 +391,9 @@ class MedtrumService : DaggerService(), BLECommCallback {
super.onConnected()
toState(AuthState())
}
-
- override fun onDisconnected() {
- super.onDisconnected()
- }
}
- // State for connect flow, could be replaced by commandState and steps in connect()
+ // State for connect flow
private inner class AuthState : State() {
val retryCounter = 0
@@ -382,11 +401,16 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached AuthState")
mPacket = AuthorizePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ scope.launch {
+ waitForResponse()
+ }
}
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
+ responseHandled = true
+ responseSuccess = true
// TODO Get pump version info
val deviceType = (mPacket as AuthorizePacket).deviceType
val swVersion = (mPacket as AuthorizePacket).swVersion
@@ -394,31 +418,31 @@ class MedtrumService : DaggerService(), BLECommCallback {
toState(GetDeviceTypeState())
} else if (mPacket?.failed == true) {
// Failure
- // retry twice
- // TODO: Test and see if this can be removed
- if (retryCounter < 2) {
- aapsLogger.error(LTag.PUMPCOMM, "AuthState failed!, retrying")
- mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
- } else {
- bleComm.disconnect("Failure")
- toState(IdleState())
- }
+ responseHandled = true
+ responseSuccess = false
+ bleComm.disconnect("Failure")
+ toState(IdleState())
}
}
}
- // State for connect flow, could be replaced by commandState and steps in connect()
+ // State for connect flow
private inner class GetDeviceTypeState : State() {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached GetDeviceTypeState")
mPacket = GetDeviceTypePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ scope.launch {
+ waitForResponse()
+ }
}
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
+ responseHandled = true
+ responseSuccess = true
// TODO Get device type and SN
val deviceType = (mPacket as GetDeviceTypePacket).deviceType
val deviceSN = (mPacket as GetDeviceTypePacket).deviceSN
@@ -426,24 +450,31 @@ class MedtrumService : DaggerService(), BLECommCallback {
toState(GetTimeState())
} else if (mPacket?.failed == true) {
// Failure
+ responseHandled = true
+ responseSuccess = false
bleComm.disconnect("Failure")
toState(IdleState())
}
}
}
- // State for connect flow, could be replaced by commandState and steps in connect()
+ // State for connect flow
private inner class GetTimeState : State() {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached GetTimeState")
mPacket = GetTimePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ scope.launch {
+ waitForResponse()
+ }
}
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
+ responseHandled = true
+ responseSuccess = true
val currTime = dateUtil.nowWithoutMilliseconds()
if (abs(medtrumPump.lastTimeReceivedFromPump - currTime) <= T.secs(5).msecs()) { // Allow 5 sec deviation
toState(SynchronizeState())
@@ -460,90 +491,120 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
} else if (mPacket?.failed == true) {
// Failure
+ responseHandled = true
+ responseSuccess = false
bleComm.disconnect("Failure")
toState(IdleState())
}
}
}
- // State for connect flow, could be replaced by commandState and steps in connect()
+ // State for connect flow
private inner class SetTimeState : State() {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SetTimeState")
mPacket = SetTimePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ scope.launch {
+ waitForResponse()
+ }
}
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
+ responseHandled = true
+ responseSuccess = true
toState(SetTimeZoneState())
} else if (mPacket?.failed == true) {
// Failure
+ responseHandled = true
+ responseSuccess = false
bleComm.disconnect("Failure")
toState(IdleState())
}
}
}
- // State for connect flow, could be replaced by commandState and steps in connect()
+ // State for connect flow
private inner class SetTimeZoneState : State() {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SetTimeZoneState")
mPacket = SetTimeZonePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ scope.launch {
+ waitForResponse()
+ }
}
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
+ responseHandled = true
+ responseSuccess = true
toState(SynchronizeState())
} else if (mPacket?.failed == true) {
// Failure
+ responseHandled = true
+ responseSuccess = false
bleComm.disconnect("Failure")
toState(IdleState())
}
}
}
- // State for connect flow, could be replaced by commandState and steps in connect()
+ // State for connect flow
private inner class SynchronizeState : State() {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SynchronizeState")
mPacket = SynchronizePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ scope.launch {
+ waitForResponse()
+ }
}
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
+ responseHandled = true
+ responseSuccess = true
toState(SubscribeState())
} else if (mPacket?.failed == true) {
// Failure
+ responseHandled = true
+ responseSuccess = false
bleComm.disconnect("Failure")
toState(IdleState())
}
}
}
- // State for connect flow, could be replaced by commandState and steps in connect()
+ // State for connect flow
private inner class SubscribeState : State() {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached SubscribeState")
mPacket = SubscribePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
+ scope.launch {
+ waitForResponse()
+ }
}
override fun onIndication(data: ByteArray) {
if (mPacket?.handleResponse(data) == true) {
// Succes!
+ responseHandled = true
+ responseSuccess = true
toState(ReadyState())
} else if (mPacket?.failed == true) {
// Failure
+ responseHandled = true
+ responseSuccess = false
bleComm.disconnect("Failure")
toState(IdleState())
}
@@ -566,9 +627,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
// This state is when a command is send and we wait for a response for that command
private inner class CommandState : State() {
- private var responseHandled = false
- private var responseSuccess = false
-
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached CommandState")
}
@@ -586,34 +644,5 @@ class MedtrumService : DaggerService(), BLECommCallback {
toState(ReadyState())
}
}
-
- override fun onDisconnected() {
- super.onDisconnected()
- responseHandled = true
- responseSuccess = false
- }
-
- override fun onSendMessageError(reason: String) {
- super.onSendMessageError(reason)
- responseHandled = true
- responseSuccess = false
- }
-
- override fun waitForResponse(): Boolean {
- val startTime = System.currentTimeMillis()
- val timeoutMillis = T.secs(45).msecs()
- while (!responseHandled) {
- if (System.currentTimeMillis() - startTime > timeoutMillis) {
- // If we haven't received a response in the specified time, assume the command failed
- aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service CommandState timeout")
- // Disconnect to cancel any outstanding commands and go back to ready state
- bleComm.disconnect("Timeout")
- toState(ReadyState())
- return false
- }
- Thread.sleep(100)
- }
- return responseSuccess
- }
}
}
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index ef2b5de75e..dd2665e7b2 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -7,7 +7,6 @@
medtrum_session_token
patch_id
actual_basal_profile
- last_basal_type
current_sequence_number
synced_sequence_number
From cd65639abb1e68b21908f2f24d0397959fcea83c Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Mon, 29 May 2023 20:05:21 +0200
Subject: [PATCH 026/116] Only update basal from Notification when it has
changed
---
.../java/info/nightscout/pump/medtrum/MedtrumPlugin.kt | 2 --
.../java/info/nightscout/pump/medtrum/MedtrumPump.kt | 1 +
.../pump/medtrum/comm/packets/NotificationPacket.kt | 9 ++++++---
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 2d154856c5..80ba861529 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -151,8 +151,6 @@ import kotlin.math.round
override fun connect(reason: String) {
if (medtrumPump.patchActivated) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
- aapsLogger.debug(LTag.PUMP, "Medtrum connect - service::$medtrumService")
- // aapsLogger.debug(LTag.PUMP, "Medtrum connect - mDeviceSN:$mDeviceSN")
if (medtrumService != null) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
val success = medtrumService?.connect(reason) ?: false
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 330bbdaaef..6c85391c21 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -306,6 +306,7 @@ class MedtrumPump @Inject constructor(
LTag.PUMP,
"handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + "receivedTime: $receivedTime"
)
+ @Suppress("UNNECESSARY_SAFE_CALL") // Safe call to allow mocks to retun null
val expectedTemporaryBasal = pumpSync.expectedPumpState()?.temporaryBasal
if (basalType.isTempBasal() && expectedTemporaryBasal?.pumpId != basalStartTime) {
// Note: temporaryBasalInfo will be removed from temporaryBasalStorage after this call
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index 6c9695f624..7b231ac4b8 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -114,15 +114,18 @@ class NotificationPacket(val injector: HasAndroidInjector) {
val basalType = enumValues()[data.copyOfRange(offset, offset + 1).toInt()]
var basalSequence = data.copyOfRange(offset + 1, offset + 3).toInt()
var basalPatchId = data.copyOfRange(offset + 3, offset + 5).toLong()
- var basalTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset + 5, offset + 9).toLong())
+ var basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset + 5, offset + 9).toLong())
var basalRateAndDelivery = data.copyOfRange(offset + 9, offset + 12).toInt()
var basalRate = (basalRateAndDelivery and 0xFFF) * 0.05
var basalDelivery = (basalRateAndDelivery shr 12) * 0.05
aapsLogger.debug(
LTag.PUMPCOMM,
- "Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal time: $basalTime, basal rate: $basalRate, basal delivery: $basalDelivery"
+ "Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal time: $basalStartTime, basal rate: $basalRate, basal delivery: $basalDelivery"
)
- medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalTime)
+ // Don't spam with basal updates here, only if the running basal rate has changed, or a new basal is set
+ if (medtrumPump.lastBasalRate != basalRate || medtrumPump.lastBasalStartTime != basalStartTime) {
+ medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
+ }
offset += 12
}
From aadf40b6fbcf7239c7b58d98684c34545edb66e3 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 30 May 2023 13:05:32 +0200
Subject: [PATCH 027/116] Fix time in getHourlyBasalFromMedtrumProfileArray()
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 16 +++++---
.../pump/medtrum/MedtrumPumpTest.kt | 39 ++++++++++++-------
2 files changed, 36 insertions(+), 19 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 6c85391c21..c68b801e83 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -19,6 +19,7 @@ import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import java.util.GregorianCalendar
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.round
@@ -160,12 +161,13 @@ class MedtrumPump @Inject constructor(
var bolusDone = false // success end
// Last basal status update
+ // TODO maybe make basal parameters private? So we are forced to update trough handleBasalStatusUpdate
var lastBasalSequence = 0
var lastBasalPatchId = 0L
var lastBasalStartTime = 0L
val baseBasalRate: Double
- get() = getCurrentHourlyBasalFromMedtrumProfileArray(actualBasalProfile)
+ get() = getHourlyBasalFromMedtrumProfileArray(actualBasalProfile, dateUtil.now())
// TBR status
val tempBasalInProgress: Boolean
@@ -252,15 +254,17 @@ class MedtrumPump @Inject constructor(
return (list.size).toByteArray(1) + basals
}
- fun getCurrentHourlyBasalFromMedtrumProfileArray(basalProfile: ByteArray): Double {
+ fun getHourlyBasalFromMedtrumProfileArray(basalProfile: ByteArray, timestamp: Long): Double {
val basalCount = basalProfile[0].toInt()
var basal = 0.0
if (basalProfile.size < 4 || (basalProfile.size - 1) % 3 != 0 || basalCount > 24) {
- aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: No valid basal profile set")
+ aapsLogger.debug(LTag.PUMP, "getHourlyBasalFromMedtrumProfileArray: No valid basal profile set")
return basal
}
- val hourOfDayMinutes = dateUtil.dateAndTimeString(dateUtil.now()).substring(11, 13).toInt() * 60 + dateUtil.dateAndTimeString(dateUtil.now()).substring(14, 16).toInt()
+ val date = GregorianCalendar()
+ date.timeInMillis = timestamp
+ val hourOfDayMinutes = date.get(GregorianCalendar.HOUR_OF_DAY) * 60 + date.get(GregorianCalendar.MINUTE)
for (index in 0 until basalCount) {
val currentIndex = 1 + (index * 3)
@@ -278,10 +282,10 @@ class MedtrumPump @Inject constructor(
if (hourOfDayMinutes in startMinutes until endMinutes) {
basal = rate
- aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: basal: $basal")
+ aapsLogger.debug(LTag.PUMP, "getHourlyBasalFromMedtrumProfileArray: basal: $basal")
break
}
- // aapsLogger.debug(LTag.PUMP, "getCurrentHourlyBasalFromMedtrumProfileArray: rate: $rate, startMinutes: $startMinutes, endMinutes: $endMinutes")
+ // aapsLogger.debug(LTag.PUMP, "getHourlyBasalFromMedtrumProfileArray: rate: $rate, startMinutes: $startMinutes, endMinutes: $endMinutes")
}
return basal
}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
index 5dbfe34f78..ed9771966c 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/MedtrumPumpTest.kt
@@ -2,14 +2,12 @@ package info.nightscout.pump.medtrum
import info.nightscout.core.extensions.pureProfileFromJson
import info.nightscout.core.profile.ProfileSealed
-import info.nightscout.shared.utils.DateUtil
import org.json.JSONObject
import org.junit.jupiter.api.Test
import org.junit.Assert.*
-import org.mockito.Mock
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.`when`
-import org.mockito.kotlin.any
+import java.time.LocalDate
+import java.time.LocalTime
+import java.time.ZoneId
class MedtrumPumpTest : MedtrumTestBase() {
@@ -73,19 +71,34 @@ class MedtrumPumpTest : MedtrumTestBase() {
val profile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(profileJSON), dateUtil)!!)
val profileArray = medtrumPump.buildMedtrumProfileArray(profile)
+ val localDate = LocalDate.of(2023, 1, 1)
+
// For 03:59
- `when`(dateUtil.dateAndTimeString((any()))).thenReturn("2023-01-01T03:59:00.000Z")
- val result = medtrumPump.getCurrentHourlyBasalFromMedtrumProfileArray(profileArray!!)
+ val localTime0399 = LocalTime.of(3, 59)
+ val zonedDateTime0399 = localDate.atTime(localTime0399).atZone(ZoneId.systemDefault())
+ val time0399 = zonedDateTime0399.toInstant().toEpochMilli()
+ val result = medtrumPump.getHourlyBasalFromMedtrumProfileArray(profileArray!!, time0399)
assertEquals(2.1, result, 0.01)
+ // For 22:30
+ val localTime2230 = LocalTime.of(22, 30)
+ val zonedDateTime2230 = localDate.atTime(localTime2230).atZone(ZoneId.systemDefault())
+ val time2230 = zonedDateTime2230.toInstant().toEpochMilli()
+ val result1 = medtrumPump.getHourlyBasalFromMedtrumProfileArray(profileArray!!, time2230)
+ assertEquals(1.7, result1, 0.01)
+
// For 23:59
- `when`(dateUtil.dateAndTimeString((any()))).thenReturn("2023-01-01T23:59:59.999Z")
- val result1 = medtrumPump.getCurrentHourlyBasalFromMedtrumProfileArray(profileArray!!)
- assertEquals(2.0, result1, 0.01)
+ val localTime2359 = LocalTime.of(23, 59)
+ val zonedDateTime2359 = localDate.atTime(localTime2359).atZone(ZoneId.systemDefault())
+ val time2359 = zonedDateTime2359.toInstant().toEpochMilli()
+ val result2 = medtrumPump.getHourlyBasalFromMedtrumProfileArray(profileArray!!, time2359)
+ assertEquals(2.0, result2, 0.01)
// For 00:00
- `when`(dateUtil.dateAndTimeString((any()))).thenReturn("2023-01-01T00:00:00.000Z")
- val result2 = medtrumPump.getCurrentHourlyBasalFromMedtrumProfileArray(profileArray!!)
- assertEquals(2.1, result2, 0.01)
+ val localTime0000 = LocalTime.of(0, 0)
+ val zonedDateTime0000 = localDate.atTime(localTime0000).atZone(ZoneId.systemDefault())
+ val time0000 = zonedDateTime0000.toInstant().toEpochMilli()
+ val result3 = medtrumPump.getHourlyBasalFromMedtrumProfileArray(profileArray!!, time0000)
+ assertEquals(2.1, result3, 0.01)
}
}
From 4a1eded8e595e0d40d6c6d66234ea85704d183e4 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 1 Jun 2023 08:54:40 +0200
Subject: [PATCH 028/116] Added extra checks and logging
---
.../pump/medtrum/services/BLEComm.kt | 19 ++++++++++++-------
.../pump/medtrum/services/MedtrumService.kt | 9 ++++++++-
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 3ff7d00acb..c934a84ccf 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -125,10 +125,6 @@ class BLEComm @Inject internal constructor(
.build()
val filters = mutableListOf()
-
- isConnected = false
- isConnecting = true
-
// Find our Medtrum Device!
filters.add(
ScanFilter.Builder().setDeviceName("MT").build()
@@ -158,16 +154,16 @@ class BLEComm @Inject internal constructor(
return false
}
+ isConnected = false
+ isConnecting = true
if (mDevice != null && mDeviceSN == deviceSN) {
// Skip scanning and directly connect to gatt
aapsLogger.debug(LTag.PUMPBTCOMM, "Skipping scan and directly connecting to gatt")
- isConnecting = true
connectGatt(mDevice!!)
} else {
// Scan for device
aapsLogger.debug(LTag.PUMPBTCOMM, "Scanning for device")
mDeviceSN = deviceSN
- isConnecting = true
startScan()
}
@@ -180,8 +176,14 @@ class BLEComm @Inject internal constructor(
private fun connectGatt(device: BluetoothDevice) {
// Reset sequence counter
mWriteSequenceNumber = 0
- mBluetoothGatt =
+ if (mBluetoothGatt == null) {
+ mBluetoothGatt =
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
+ } else {
+ // Already connected?, this should not happen force disconnect
+ aapsLogger.error(LTag.PUMPBTCOMM, "connectGatt, mBluetoothGatt is not null")
+ disconnect("connectGatt, mBluetoothGatt is not null")
+ }
}
@SuppressLint("MissingPermission")
@@ -200,8 +202,10 @@ class BLEComm @Inject internal constructor(
SystemClock.sleep(100)
}
if (isConnected) {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Connected, disconnecting")
mBluetoothGatt?.disconnect()
} else {
+ aapsLogger.debug(LTag.PUMPBTCOMM, "Not connected, closing gatt")
close()
isConnected = false
mCallback?.onBLEDisconnected()
@@ -212,6 +216,7 @@ class BLEComm @Inject internal constructor(
@Synchronized fun close() {
aapsLogger.debug(LTag.PUMPBTCOMM, "BluetoothAdapter close")
mBluetoothGatt?.close()
+ SystemClock.sleep(100)
mBluetoothGatt = null
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 91facb8a59..6ca8bc5c42 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -72,6 +72,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
@Inject lateinit var pumpSync: PumpSync
@Inject lateinit var dateUtil: DateUtil
+ companion object {
+ // TODO: Test and further increase?
+ private const val COMMAND_TIMEOUT_SEC: Long = 60
+ }
+
val timeUtil = MedtrumTimeUtil()
private val disposable = CompositeDisposable()
@@ -272,10 +277,12 @@ class MedtrumService : DaggerService(), BLECommCallback {
/** BLECommCallbacks */
override fun onBLEConnected() {
+ aapsLogger.debug(LTag.PUMPCOMM, "<<<<< onBLEConnected")
currentState.onConnected()
}
override fun onBLEDisconnected() {
+ aapsLogger.debug(LTag.PUMPCOMM, "<<<<< onBLEDisconnected")
currentState.onDisconnected()
}
@@ -358,7 +365,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun waitForResponse(): Boolean {
val startTime = System.currentTimeMillis()
- val timeoutMillis = T.secs(45).msecs()
+ val timeoutMillis = T.secs(COMMAND_TIMEOUT_SEC).msecs()
while (!responseHandled) {
if (System.currentTimeMillis() - startTime > timeoutMillis) {
// If we haven't received a response in the specified time, assume the command failed
From 9860c7aac315b4c57f29ab9f556002fc800e7134 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Fri, 2 Jun 2023 21:27:45 +0200
Subject: [PATCH 029/116] Improve tbr syncing
---
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 5 +-
.../comm/packets/CancelTempBasalPacket.kt | 16 +++++
.../pump/medtrum/services/MedtrumService.kt | 61 ++++++++++++-------
pump/medtrum/src/main/res/values/strings.xml | 1 +
.../comm/packets/CancelTempBasalPacketTest.kt | 2 +
5 files changed, 63 insertions(+), 22 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 80ba861529..6d5b3cd4b2 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -173,7 +173,10 @@ import kotlin.math.round
override fun getPumpStatus(reason: String) {
aapsLogger.debug(LTag.PUMP, "Medtrum getPumpStatus - reason:$reason")
if (isInitialized()) {
- medtrumService?.readPumpStatus()
+ val connectionOK = medtrumService?.readPumpStatus() ?: false
+ if (connectionOK == false) {
+ aapsLogger.error(LTag.PUMP, "Medtrum getPumpStatus failed")
+ }
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
index b6bb78c399..3503c4a0fe 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
@@ -1,17 +1,22 @@
package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
+import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.comm.enums.CommandType.CANCEL_TEMP_BASAL
import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
+import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.utils.DateUtil
import javax.inject.Inject
class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@Inject lateinit var medtrumPump: MedtrumPump
+ @Inject lateinit var pumpSync: PumpSync
+ @Inject lateinit var dateUtil: DateUtil
companion object {
@@ -42,6 +47,17 @@ class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(inject
val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
+
+ pumpSync.syncStopTemporaryBasalWithPumpId(
+ timestamp = basalStartTime, // Time of normal basal start = time of tbr end
+ endPumpId = basalStartTime,
+ pumpType = medtrumPump.pumpType,
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ aapsLogger.warn(
+ LTag.PUMPCOMM,
+ "CancelTempBasalPacket: EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) "
+ )
}
return success
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 6ca8bc5c42..4df7931204 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -74,7 +74,9 @@ class MedtrumService : DaggerService(), BLECommCallback {
companion object {
// TODO: Test and further increase?
- private const val COMMAND_TIMEOUT_SEC: Long = 60
+ private const val COMMAND_DEFAULT_TIMEOUT_SEC: Long = 60
+ private const val COMMAND_SYNC_TIMEOUT_SEC: Long = 120
+ private const val COMMAND_CONNECTING_TIMEOUT_SEC: Long = 30
}
val timeUtil = MedtrumTimeUtil()
@@ -142,7 +144,12 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun deactivatePatch(): Boolean {
- return sendPacketAndGetResponse(StopPatchPacket(injector))
+ var result = true
+ if (medtrumPump.tempBasalInProgress) {
+ result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
+ }
+ if (result) result = sendPacketAndGetResponse(StopPatchPacket(injector))
+ return result
}
fun stopConnecting() {
@@ -227,8 +234,13 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
if (result) result = sendPacketAndGetResponse(SetTempBasalPacket(injector, absoluteRate, durationInMinutes))
- // Get history records, this will update the pump state
- if (result) result = syncRecords()
+ // Get history records, this will update the prevoius basals
+ // Do not call update status directly, reconnection may be needed
+ commandQueue.readStatus(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus), object : Callback() {
+ override fun run() {
+ rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus)))
+ }
+ })
return result
}
@@ -236,8 +248,13 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun cancelTempBasal(): Boolean {
var result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
- // Get history records, this will update the pump state
- if (result) result = syncRecords()
+ // Get history records, this will update the prevoius basals
+ // Do not call update status directly, reconnection may be needed
+ commandQueue.readStatus(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus), object : Callback() {
+ override fun run() {
+ rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus)))
+ }
+ })
return result
}
@@ -266,11 +283,13 @@ class MedtrumService : DaggerService(), BLECommCallback {
/** This gets the history records from the pump */
private fun syncRecords(): Boolean {
aapsLogger.debug(LTag.PUMP, "syncRecords: called!, syncedSequenceNumber: ${medtrumPump.syncedSequenceNumber}, currentSequenceNumber: ${medtrumPump.currentSequenceNumber}")
- var result = false
+ var result = true
// Note: medtrum app fetches all records when they sync?
- for (sequence in medtrumPump.syncedSequenceNumber..medtrumPump.currentSequenceNumber) {
- result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
- if (!result) break
+ if (medtrumPump.syncedSequenceNumber < medtrumPump.currentSequenceNumber) {
+ for (sequence in (medtrumPump.syncedSequenceNumber + 1)..medtrumPump.currentSequenceNumber) {
+ result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
+ if (result == false) break
+ }
}
return result
}
@@ -324,13 +343,13 @@ class MedtrumService : DaggerService(), BLECommCallback {
currentState.onEnter()
}
- private fun sendPacketAndGetResponse(packet: MedtrumPacket): Boolean {
+ private fun sendPacketAndGetResponse(packet: MedtrumPacket, timeout: Long = COMMAND_DEFAULT_TIMEOUT_SEC): Boolean {
var result = false
if (currentState is ReadyState) {
toState(CommandState())
mPacket = packet
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
- result = currentState.waitForResponse()
+ result = currentState.waitForResponse(timeout)
} else {
aapsLogger.error(LTag.PUMPCOMM, "Send packet attempt when in non Ready state")
}
@@ -363,9 +382,9 @@ class MedtrumService : DaggerService(), BLECommCallback {
toState(IdleState())
}
- fun waitForResponse(): Boolean {
+ fun waitForResponse(timeout: Long): Boolean {
val startTime = System.currentTimeMillis()
- val timeoutMillis = T.secs(COMMAND_TIMEOUT_SEC).msecs()
+ val timeoutMillis = T.secs(timeout).msecs()
while (!responseHandled) {
if (System.currentTimeMillis() - startTime > timeoutMillis) {
// If we haven't received a response in the specified time, assume the command failed
@@ -409,7 +428,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
mPacket = AuthorizePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
scope.launch {
- waitForResponse()
+ waitForResponse(COMMAND_CONNECTING_TIMEOUT_SEC)
}
}
@@ -441,7 +460,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
mPacket = GetDeviceTypePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
scope.launch {
- waitForResponse()
+ waitForResponse(COMMAND_CONNECTING_TIMEOUT_SEC)
}
}
@@ -473,7 +492,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
mPacket = GetTimePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
scope.launch {
- waitForResponse()
+ waitForResponse(COMMAND_CONNECTING_TIMEOUT_SEC)
}
}
@@ -514,7 +533,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
mPacket = SetTimePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
scope.launch {
- waitForResponse()
+ waitForResponse(COMMAND_CONNECTING_TIMEOUT_SEC)
}
}
@@ -542,7 +561,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
mPacket = SetTimeZonePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
scope.launch {
- waitForResponse()
+ waitForResponse(COMMAND_CONNECTING_TIMEOUT_SEC)
}
}
@@ -570,7 +589,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
mPacket = SynchronizePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
scope.launch {
- waitForResponse()
+ waitForResponse(COMMAND_CONNECTING_TIMEOUT_SEC)
}
}
@@ -598,7 +617,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
mPacket = SubscribePacket(injector)
mPacket?.getRequest()?.let { bleComm.sendMessage(it) }
scope.launch {
- waitForResponse()
+ waitForResponse(COMMAND_CONNECTING_TIMEOUT_SEC)
}
}
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index dd2665e7b2..7d5cbead42 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -47,6 +47,7 @@
Waiting for bolus end. Remaining %1$d sec.
Getting bolus status
+ Getting temporary basal status
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
index f5d034b212..208b1b9921 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacketTest.kt
@@ -16,6 +16,8 @@ class CancelTempBasalPacketTest : MedtrumTestBase() {
if (it is CancelTempBasalPacket) {
it.aapsLogger = aapsLogger
it.medtrumPump = medtrumPump
+ it.pumpSync = pumpSync
+ it.dateUtil = dateUtil
}
}
}
From 6ccfb734d7a1b7bb080dccdb16522012923901bb Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 4 Jun 2023 17:33:33 +0200
Subject: [PATCH 030/116] Only update lastDataTime on successful readStatus
---
.../java/info/nightscout/pump/medtrum/MedtrumPlugin.kt | 5 +----
.../java/info/nightscout/pump/medtrum/MedtrumPump.kt | 9 +++++----
.../pump/medtrum/comm/packets/NotificationPacket.kt | 2 +-
.../nightscout/pump/medtrum/services/MedtrumService.kt | 1 +
4 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 6d5b3cd4b2..ecca2d8712 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -210,10 +210,7 @@ import kotlin.math.round
return result
}
- override fun lastDataTime(): Long {
- return medtrumPump.lastTimeReceivedFromPump
- }
-
+ override fun lastDataTime(): Long = medtrumPump.lastConnection
override val baseBasalRate: Double
get() = medtrumPump.baseBasalRate
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index c68b801e83..9478419527 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -140,10 +140,11 @@ class MedtrumPump @Inject constructor(
val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection
- var lastTimeReceivedFromPump = 0L // Time in seconds!
- var suspendTime = 0L // Time in seconds!
- var patchStartTime = 0L // Time in seconds!
- var patchAge = 0L // Time in seconds!
+ var lastConnection = 0L // Time in ms!
+ var lastTimeReceivedFromPump = 0L // Time in ms! // TODO: Consider removing as is not used?
+ var suspendTime = 0L // Time in ms!
+ var patchStartTime = 0L // Time in ms!
+ var patchAge = 0L // Time in seconds?! // TODO: Not used
var batteryVoltage_A = 0.0
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index 7b231ac4b8..b3bf3c3308 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -87,7 +87,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_SUSPEND != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Suspend notification received")
- medtrumPump.suspendTime = data.copyOfRange(offset, offset + 4).toLong()
+ medtrumPump.suspendTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset, offset + 4).toLong())
aapsLogger.debug(LTag.PUMPCOMM, "Suspend time: ${medtrumPump.suspendTime}")
offset += 4
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 4df7931204..7ed869956b 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -171,6 +171,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.error(LTag.PUMPCOMM, "Failed to sync records")
return
}
+ if (result) medtrumPump.lastConnection = System.currentTimeMillis()
}
fun setBolus(insulin: Double, t: EventOverviewBolusProgress.Treatment): Boolean {
From 932f651e5762547a9b9d3abd10f1bf0664d4dd6f Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 4 Jun 2023 19:17:55 +0200
Subject: [PATCH 031/116] Workaround for connection timeout alarm not alarming
---
.../info/nightscout/androidaps/receivers/KeepAliveWorker.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveWorker.kt b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveWorker.kt
index 29e9207399..56c500fdc5 100644
--- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveWorker.kt
+++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveWorker.kt
@@ -191,7 +191,7 @@ class KeepAliveWorker(
}
if (loop.isDisconnected) {
// do nothing if pump is disconnected
- } else if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile) || (runningProfile is ProfileSealed.EPS && runningProfile.value.originalEnd < dateUtil.now())) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
+ } else if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile) /*|| (runningProfile is ProfileSealed.EPS && runningProfile.value.originalEnd < dateUtil.now())*/) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
rxBus.send(EventProfileSwitchChanged())
} else if (isStatusOutdated && !pump.isBusy()) {
lastReadStatus = now
From bad4d7a7f428bb432e9d46c6ccceaaed0bba53ad Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 8 Jun 2023 11:27:55 +0200
Subject: [PATCH 032/116] Improve activation flow
---
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 9 +++--
.../nightscout/pump/medtrum/MedtrumPump.kt | 38 ++++---------------
.../pump/medtrum/comm/enums/BasalType.kt | 4 --
.../pump/medtrum/comm/enums/BolusType.kt | 4 --
.../comm/packets/NotificationPacket.kt | 6 ++-
.../medtrum/comm/packets/SynchronizePacket.kt | 5 ++-
.../pump/medtrum/services/MedtrumService.kt | 19 +++++++---
.../medtrum/ui/MedtrumOverviewFragment.kt | 10 ++---
.../medtrum/ui/viewmodel/BaseViewModel.kt | 1 +
.../medtrum/ui/viewmodel/MedtrumViewModel.kt | 28 +++++---------
pump/medtrum/src/main/res/values/strings.xml | 2 +-
11 files changed, 52 insertions(+), 74 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index ecca2d8712..5cbdbd4f4a 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -139,7 +139,7 @@ import kotlin.math.round
override fun isConnected(): Boolean {
// This is a workaround to prevent AAPS to trigger connects when we have no patch activated
- return if (!medtrumPump.patchActivated) true else medtrumService?.isConnected ?: false
+ return if (!isInitialized()) true else medtrumService?.isConnected ?: false
}
override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false
@@ -149,7 +149,7 @@ import kotlin.math.round
}
override fun connect(reason: String) {
- if (medtrumPump.patchActivated) {
+ if (isInitialized()) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
if (medtrumService != null) {
aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
@@ -167,7 +167,10 @@ import kotlin.math.round
}
override fun stopConnecting() {
- medtrumService?.stopConnecting()
+ if (isInitialized()) {
+ aapsLogger.debug(LTag.PUMP, "Medtrum stopConnecting")
+ medtrumService?.stopConnecting()
+ }
}
override fun getPumpStatus(reason: String) {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 9478419527..d2d2d28611 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -42,13 +42,6 @@ class MedtrumPump @Inject constructor(
_connectionState.value = value
}
- /** Patch activated state, mainly for UI, but also controls the connection flow,
- * if patch is not activated, AAPS cannot connect to the pump, we can then connect trough the activation flow.
- * Note: this is also saved in SP, by the set functions
- */
- private var _patchActivated = false
- val patchActivated: Boolean
- get() = _patchActivated
// Pump state flow
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
@@ -57,6 +50,7 @@ class MedtrumPump @Inject constructor(
get() = _pumpState.value
set(value) {
_pumpState.value = value
+ sp.putInt(R.string.key_pump_state, value.state.toInt())
}
// Prime progress as state flow
@@ -189,11 +183,11 @@ class MedtrumPump @Inject constructor(
init {
// Load stuff from SP
- _patchActivated = sp.getBoolean(R.string.key_patch_activated, false)
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
_patchId = sp.getLong(R.string.key_patch_id, 0L)
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
+ _pumpState.value = MedtrumPumpState.fromByte(sp.getInt(R.string.key_pump_state, MedtrumPumpState.NONE.state.toInt()).toByte())
val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
try {
@@ -202,12 +196,6 @@ class MedtrumPump @Inject constructor(
aapsLogger.error(LTag.PUMP, "Error decoding basal profile from SP: $encodedString")
}
- if (patchActivated) {
- aapsLogger.debug(LTag.PUMP, "changePump: Patch is already activated, setting as ACTIVE")
- // Set inital status as active will be updated on first connection
- pumpState = MedtrumPumpState.ACTIVE
- }
-
loadUserSettingsFromSP()
}
@@ -225,20 +213,6 @@ class MedtrumPump @Inject constructor(
}
}
- fun setPatchActivatedState(activated: Boolean) {
- aapsLogger.debug(LTag.PUMP, "setPatchActivatedState: $activated")
- _patchActivated = activated
- sp.putBoolean(R.string.key_patch_activated, activated)
- }
-
- /** When the activation/deactivation screen, and the connection flow needs to be controlled,
- * this can be used to set the ActivatedState without saving to SP, So when app is force closed the state is still maintained
- */
- fun setPatchActivatedStateTemp(activated: Boolean) {
- aapsLogger.debug(LTag.PUMP, "setPatchActivatedStateTemp: $activated")
- _patchActivated = activated
- }
-
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
val list = nsProfile.getBasalValues()
var basals = byteArrayOf()
@@ -348,14 +322,16 @@ class MedtrumPump @Inject constructor(
LTag.PUMPCOMM,
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) expectedTemporaryBasal: $expectedTemporaryBasal"
)
- } else if (basalType == BasalType.NONE && expectedTemporaryBasal?.pumpId != basalStartTime) { // Also some sort of suspend or unkown by pump
+ } else if (basalType == BasalType.NONE && expectedTemporaryBasal?.rate != basalRate && expectedTemporaryBasal?.duration != T.mins(4800).msecs()) {
+ // Pump suspended, set fake TBR
+ // TODO: Maybe move this to separate function?
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
- timestamp = basalStartTime,
+ timestamp = dateUtil.now(),
rate = basalRate,
duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
- pumpId = basalStartTime,
+ pumpId = dateUtil.now(),
pumpType = pumpType,
pumpSerial = pumpSN.toString(radix = 16)
)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BasalType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BasalType.kt
index 7379b03609..f35ff3b4ba 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BasalType.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BasalType.kt
@@ -44,10 +44,6 @@ enum class BasalType {
AUTO_MODE_EXERCISE_START,
AUTO_MODE_EXERCISE_EXIT;
- fun getValue(): Int {
- return ordinal
- }
-
fun isTempBasal(): Boolean {
return this == ABSOLUTE_TEMP || this == RELATIVE_TEMP
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
index 77634d5fb6..ef245d1805 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
@@ -5,8 +5,4 @@ enum class BolusType {
NORMAL,
EXTEND,
COMBINATION;
-
- fun getValue(): Int {
- return ordinal
- }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index b3bf3c3308..c8f1a215fa 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -68,8 +68,10 @@ class NotificationPacket(val injector: HasAndroidInjector) {
val state = MedtrumPumpState.fromByte(notification[0])
aapsLogger.debug(LTag.PUMPCOMM, "Notification state: $state, current state: ${medtrumPump.pumpState}")
- // TODO: Do we need to emit an event on state change?
- medtrumPump.pumpState = state
+ if (state != medtrumPump.pumpState) {
+ aapsLogger.debug(LTag.PUMPCOMM, "State changed from ${medtrumPump.pumpState} to $state")
+ medtrumPump.pumpState = state
+ }
if (notification.size > NOTIF_STATE_END) {
handleMaskedMessage(notification.copyOfRange(NOTIF_STATE_END, notification.size))
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
index 19ff644a91..e2c80fe7dc 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
@@ -36,8 +36,11 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
if (success) {
var state = MedtrumPumpState.fromByte(data[RESP_STATE_START])
- medtrumPump.pumpState = state
aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: state: $state")
+ if (state != medtrumPump.pumpState) {
+ aapsLogger.debug(LTag.PUMPCOMM, "State changed from ${medtrumPump.pumpState} to $state")
+ medtrumPump.pumpState = state
+ }
var fieldMask = data.copyOfRange(RESP_FIELDS_START, RESP_FIELDS_END).toInt()
var syncData = data.copyOfRange(RESP_SYNC_DATA_START, data.size)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 7ed869956b..da4fa3d3f3 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -123,7 +123,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.debug(LTag.PUMP, "connect: called from: $from")
if (currentState is IdleState) {
medtrumPump.connectionState = ConnectionState.CONNECTING
- if (medtrumPump.patchActivated) {
+ if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING))
}
return bleComm.connect(from, medtrumPump.pumpSN)
@@ -149,6 +149,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
}
if (result) result = sendPacketAndGetResponse(StopPatchPacket(injector))
+ // Synchronize after deactivation to get update status
+ if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
return result
}
@@ -162,8 +164,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun readPumpStatus() {
// Most of these things are already done when a connection is setup, but wo dont know how long the pump was connected for?
+
+ // Send a poll patch, to workaround connection losses?
+ var result = sendPacketAndGetResponse(PollPatchPacket(injector))
// So just do a syncronize to make sure we have the latest data
- var result = sendPacketAndGetResponse(SynchronizePacket(injector))
+ if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
// Sync records (based on the info we have from the sync)
if (result) result = syncRecords()
@@ -288,7 +293,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Note: medtrum app fetches all records when they sync?
if (medtrumPump.syncedSequenceNumber < medtrumPump.currentSequenceNumber) {
for (sequence in (medtrumPump.syncedSequenceNumber + 1)..medtrumPump.currentSequenceNumber) {
- result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
+ // Send a poll patch, to workaround connection losses?
+ result = sendPacketAndGetResponse(PollPatchPacket(injector))
+ SystemClock.sleep(100)
+ // Get our record
+ if (result) result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
if (result == false) break
}
}
@@ -375,7 +384,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun onDisconnected() {
aapsLogger.debug(LTag.PUMPCOMM, "onDisconnected")
medtrumPump.connectionState = ConnectionState.DISCONNECTED
- if (medtrumPump.patchActivated) {
+ if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
}
responseHandled = true
@@ -645,7 +654,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!")
// Now we are fully connected and authenticated and we can start sending commands. Let AAPS know
medtrumPump.connectionState = ConnectionState.CONNECTED
- if (medtrumPump.patchActivated) {
+ if (medtrumPlugin.isInitialized()) {
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index 2e5503df3f..7d9050370d 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -44,11 +44,11 @@ class MedtrumOverviewFragment : MedtrumBaseFragment
when (evt.peekContent()) {
EventType.ACTIVATION_CLICKED -> requireContext().apply {
- val step = convertToPatchStep(medtrumPump.pumpState)
- // TODO is stil needed?
- // if (step != PatchStep.PREPARE_PATCH) {
- // aapsLogger.warn(LTag.PUMP, "MedtrumOverviewFragment: Patch already in activation process, going to $step")
- // }
+ var step = convertToPatchStep(medtrumPump.pumpState)
+ if (step == PatchStep.DEACTIVATION_COMPLETE) {
+ // Reset
+ step = PatchStep.PREPARE_PATCH
+ }
startActivity(MedtrumActivity.createIntentFromMenu(this, step))
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
index 62a214ae3a..a4b1b52831 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
@@ -36,6 +36,7 @@ abstract class BaseViewModel : ViewModel() {
MedtrumPumpState.PRIMING -> PatchStep.PRIME
MedtrumPumpState.PRIMED, MedtrumPumpState.EJECTED -> PatchStep.ATTACH_PATCH
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> PatchStep.COMPLETE
+ MedtrumPumpState.STOPPED -> PatchStep.DEACTIVATION_COMPLETE
else -> PatchStep.CANCEL
}
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
index 70416c5d87..e68ba4e075 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
@@ -104,12 +104,10 @@ class MedtrumViewModel @Inject constructor(
}
MedtrumPumpState.ACTIVE, MedtrumPumpState.ACTIVE_ALT -> {
- medtrumPump.setPatchActivatedState(true)
updateSetupStep(SetupStep.ACTIVATED)
}
MedtrumPumpState.STOPPED -> {
- medtrumPump.setPatchActivatedState(false)
updateSetupStep(SetupStep.STOPPED)
}
@@ -137,8 +135,7 @@ class MedtrumViewModel @Inject constructor(
}
// TODO: For DEACTIVATE STATE we might want to move to force cancel screen
if (oldPatchStep == PatchStep.START_DEACTIVATION || oldPatchStep == PatchStep.DEACTIVATE) {
- // Deactivation was canceled
- medtrumPump.setPatchActivatedStateTemp(true)
+ // What to do here?
}
}
@@ -166,16 +163,16 @@ class MedtrumViewModel @Inject constructor(
}
fun preparePatch() {
- if (medtrumPump.patchActivated == true) {
- aapsLogger.warn(LTag.PUMP, "preparePatch: already activated! conflicting state?")
- // In this case user could have removed the patch without deactivating it?
- medtrumPump.setPatchActivatedState(false)
+ // New session, generate new session token, only do this when not connected
+ if (medtrumService?.isConnected == false) {
+ aapsLogger.info(LTag.PUMP, "preparePatch: new session")
+ medtrumPump.patchSessionToken = Crypt().generateRandomToken()
+ // Connect to pump
+ medtrumService?.connect("PreparePatch")
+ } else {
+ aapsLogger.error(LTag.PUMP, "preparePatch: Already connected when trying to prepare patch")
+ // Do nothing here, continue with old key and connection
}
- // New session, generate new session token
- aapsLogger.info(LTag.PUMP, "preparePatch: new session")
- medtrumPump.patchSessionToken = Crypt().generateRandomToken()
- // Connect to pump
- medtrumService?.connect("PreparePatch")
}
fun startPrime() {
@@ -201,9 +198,6 @@ class MedtrumViewModel @Inject constructor(
}
fun startDeactivation() {
- // Set active already to false, so UI can control the pump connection instead of AAPS pumpqueue
- medtrumPump.setPatchActivatedStateTemp(false)
-
// Start connecting if needed
if (medtrumService?.isConnected == true) {
updateSetupStep(SetupStep.READY_DEACTIVATE)
@@ -218,8 +212,6 @@ class MedtrumViewModel @Inject constructor(
aapsLogger.info(LTag.PUMP, "deactivatePatch: success!")
} else {
aapsLogger.info(LTag.PUMP, "deactivatePatch: failure!")
- // Check if this is needed, for now even when it failed, we assume the user will remove the patch and pumpbase
- medtrumPump.setPatchActivatedStateTemp(true) // failed to activate, set activate state to true
// TODO: State to force forget the patch or try again
updateSetupStep(SetupStep.ERROR)
}
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 7d5cbead42..f509a30030 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -3,7 +3,7 @@
snInput
medtrumpump_settings
- medtrum_patch_activated
+ pump_state
medtrum_session_token
patch_id
actual_basal_profile
From 3ae145524c5ebef2a41353ee16db508735dbb104 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 8 Jun 2023 14:25:25 +0200
Subject: [PATCH 033/116] Don't move patchStep when there is no connection
---
.../pump/medtrum/ui/viewmodel/MedtrumViewModel.kt | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
index e68ba4e075..944f14796e 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
@@ -149,7 +149,14 @@ class MedtrumViewModel @Inject constructor(
}
}
- else -> {}
+ else -> {
+ // Make sure we are connected, else dont move step
+ if (medtrumService?.isConnected == false) {
+ aapsLogger.info(LTag.PUMP, "moveStep: not connected, not moving step")
+ return
+ } else {
+ }
+ }
}
}
From ecb2c977ecbb7eb72413e74333a0c92bd200d283 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 8 Jun 2023 15:48:32 +0200
Subject: [PATCH 034/116] Alarm on pump suspended states
---
.../pump/medtrum/services/MedtrumService.kt | 67 ++++++++++++++-----
pump/medtrum/src/main/res/values/strings.xml | 1 +
2 files changed, 53 insertions(+), 15 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index da4fa3d3f3..3742448a25 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -10,10 +10,10 @@ import dagger.android.DaggerService
import dagger.android.HasAndroidInjector
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.constraints.Constraints
+import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
-import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.queue.Callback
import info.nightscout.interfaces.queue.CommandQueue
@@ -24,12 +24,11 @@ import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.comm.packets.*
-import info.nightscout.pump.medtrum.extension.toInt
-import info.nightscout.pump.medtrum.extension.toLong
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit
+import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.events.EventPumpStatusChanged
@@ -46,7 +45,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
-import java.util.*
import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.round
@@ -73,6 +71,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
@Inject lateinit var dateUtil: DateUtil
companion object {
+
// TODO: Test and further increase?
private const val COMMAND_DEFAULT_TIMEOUT_SEC: Long = 60
private const val COMMAND_SYNC_TIMEOUT_SEC: Long = 120
@@ -88,7 +87,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
private var mPacket: MedtrumPacket? = null
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
-
+
val isConnected: Boolean
get() = medtrumPump.connectionState == ConnectionState.CONNECTED
val isConnecting: Boolean
@@ -109,8 +108,45 @@ class MedtrumService : DaggerService(), BLECommCallback {
changePump()
}
}, fabricPrivacy::logException)
+ scope.launch {
+ medtrumPump.pumpStateFlow.collect { state ->
+ when (state) {
+ MedtrumPumpState.LOWBG_SUSPENDED,
+ MedtrumPumpState.LOWBG_SUSPENDED2,
+ MedtrumPumpState.AUTO_SUSPENDED,
+ MedtrumPumpState.HMAX_SUSPENDED,
+ MedtrumPumpState.DMAX_SUSPENDED,
+ MedtrumPumpState.SUSPENDED,
+ MedtrumPumpState.PAUSED,
+ MedtrumPumpState.OCCLUSION,
+ MedtrumPumpState.EXPIRED,
+ MedtrumPumpState.RESERVOIR_EMPTY,
+ MedtrumPumpState.PATCH_FAULT,
+ MedtrumPumpState.PATCH_FAULT2,
+ MedtrumPumpState.BASE_FAULT,
+ MedtrumPumpState.BATTERY_OUT,
+ MedtrumPumpState.NO_CALIBRATION -> {
+ // Pump suspended show error!
+ uiInteraction.addNotificationWithSound(
+ Notification.PUMP_ERROR,
+ rh.gs(R.string.pump_error, state.toString()),
+ Notification.URGENT,
+ info.nightscout.core.ui.R.raw.alarm
+ )
+ }
+
+ MedtrumPumpState.STOPPED -> {
+ rxBus.send(EventDismissNotification(Notification.PUMP_ERROR))
+ }
+
+ else -> {
+ // Do nothing
+ }
+ }
+ }
+ }
+
changePump()
- // TODO: We should probably listen to the pump state as well and handle some state changes? Or do we handle that in the packets or medtrumPump?
}
override fun onDestroy() {
@@ -168,7 +204,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Send a poll patch, to workaround connection losses?
var result = sendPacketAndGetResponse(PollPatchPacket(injector))
// So just do a syncronize to make sure we have the latest data
- if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
+ if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
// Sync records (based on the info we have from the sync)
if (result) result = syncRecords()
@@ -191,7 +227,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
medtrumPump.bolusProgressLastTimeStamp = dateUtil.now()
val bolusStart = System.currentTimeMillis()
-
+
val bolusingEvent = EventOverviewBolusProgress
while (medtrumPump.bolusStopped == false && result == true && medtrumPump.bolusDone == false) {
SystemClock.sleep(100)
@@ -207,7 +243,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
rxBus.send(bolusingEvent)
}
}
-
+
bolusingEvent.t = medtrumPump.bolusingTreatment
bolusingEvent.percent = 99
medtrumPump.bolusingTreatment = null
@@ -224,7 +260,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus)))
bolusingEvent.percent = 100
}
- })
+ })
return result
}
@@ -246,7 +282,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun run() {
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus)))
}
- })
+ })
return result
}
@@ -260,7 +296,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun run() {
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus)))
}
- })
+ })
return result
}
@@ -297,7 +333,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
result = sendPacketAndGetResponse(PollPatchPacket(injector))
SystemClock.sleep(100)
// Get our record
- if (result) result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
+ if (result) result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence), COMMAND_SYNC_TIMEOUT_SEC)
if (result == false) break
}
}
@@ -431,6 +467,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
// State for connect flow
private inner class AuthState : State() {
+
val retryCounter = 0
override fun onEnter() {
@@ -519,8 +556,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
LTag.PUMPCOMM,
"GetTimeState.onIndication need to set time. systemTime: $currTime PumpTime: ${medtrumPump.lastTimeReceivedFromPump} Pump Time to system time: " + timeUtil
.convertPumpTimeToSystemTimeMillis(
- medtrumPump.lastTimeReceivedFromPump
- )
+ medtrumPump.lastTimeReceivedFromPump
+ )
)
// TODO: Setting time cancels any TBR, so we need to handle that and cancel? or let AAPS handle time syncs?
toState(SetTimeState())
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index f509a30030..f665fc5dfe 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -14,6 +14,7 @@
MT
Medtrum Nano
Medtrum pump settings
+ Pump error: %1$s !!
BLE Status
From 0ce25c11903e6844376ee8498223acbdb44b46ce Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 8 Jun 2023 22:22:42 +0200
Subject: [PATCH 035/116] Make sure patch can be primed when already filled
before activation
---
.../nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
index 944f14796e..873e674116 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
@@ -170,6 +170,11 @@ class MedtrumViewModel @Inject constructor(
}
fun preparePatch() {
+ // Make sure patch step is updated when already filled
+ // TODO: Maybe a nicer solution for this
+ if (medtrumPump.pumpState == MedtrumPumpState.FILLED) {
+ updateSetupStep(SetupStep.FILLED)
+ }
// New session, generate new session token, only do this when not connected
if (medtrumService?.isConnected == false) {
aapsLogger.info(LTag.PUMP, "preparePatch: new session")
From e568ab399f45d2e9b18b22629cfea6237e8eca7c Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 10 Jun 2023 08:10:07 +0200
Subject: [PATCH 036/116] Force always to go to prepare patch on activation
---
.../pump/medtrum/ui/MedtrumOverviewFragment.kt | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index 7d9050370d..eed99396b7 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -44,12 +44,13 @@ class MedtrumOverviewFragment : MedtrumBaseFragment
when (evt.peekContent()) {
EventType.ACTIVATION_CLICKED -> requireContext().apply {
- var step = convertToPatchStep(medtrumPump.pumpState)
- if (step == PatchStep.DEACTIVATION_COMPLETE) {
- // Reset
- step = PatchStep.PREPARE_PATCH
- }
- startActivity(MedtrumActivity.createIntentFromMenu(this, step))
+ // TODO: Check what to do with this, and if we need this, it currently messes up patch is last registered as priming
+ // var step = convertToPatchStep(medtrumPump.pumpState)
+ // if (step == PatchStep.DEACTIVATION_COMPLETE) {
+ // // Reset
+ // step = PatchStep.PREPARE_PATCH
+ // }
+ startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.PREPARE_PATCH))
}
EventType.DEACTIVATION_CLICKED -> requireContext().apply {
From 8caeb4a3e0ab20843752894175e07dc8daa1e469 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 11 Jun 2023 13:37:59 +0200
Subject: [PATCH 037/116] add loadEvents(), small improvements
---
.../nightscout/interfaces/pump/Medtrum.kt | 9 +++++
.../queue/commands/CommandLoadEvents.kt | 8 ++++
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 38 +++++++++++++------
.../comm/packets/CancelTempBasalPacket.kt | 23 ++++++-----
.../medtrum/comm/packets/SynchronizePacket.kt | 4 +-
.../pump/medtrum/services/BLEComm.kt | 2 +-
.../pump/medtrum/services/MedtrumService.kt | 36 ++++++++++++------
pump/medtrum/src/main/res/values/strings.xml | 2 +
8 files changed, 86 insertions(+), 36 deletions(-)
create mode 100644 core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
new file mode 100644
index 0000000000..d17e58d45f
--- /dev/null
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
@@ -0,0 +1,9 @@
+package info.nightscout.interfaces.pump
+
+/**
+ * Functionality supported by Medtrum* pumps only
+ */
+interface Medtrum {
+
+ fun loadEvents(): PumpEnactResult // events history to build treatments from
+}
\ No newline at end of file
diff --git a/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandLoadEvents.kt b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandLoadEvents.kt
index df6fb48cef..16475adf4f 100644
--- a/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandLoadEvents.kt
+++ b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandLoadEvents.kt
@@ -4,6 +4,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.pump.Dana
import info.nightscout.interfaces.pump.Diaconn
+import info.nightscout.interfaces.pump.Medtrum
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.queue.Callback
import info.nightscout.interfaces.queue.Command
@@ -32,6 +33,13 @@ class CommandLoadEvents(
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
callback?.result(r)?.run()
}
+
+ if (pump is Medtrum) {
+ val medtrumPump = pump as Medtrum
+ val r = medtrumPump.loadEvents()
+ aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
+ callback?.result(r)?.run()
+ }
}
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.load_events)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 5cbdbd4f4a..bfef4fa928 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -17,6 +17,7 @@ import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.DetailedBolusInfo
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
+import info.nightscout.interfaces.pump.Medtrum
import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.pump.PumpPluginBase
@@ -85,7 +86,7 @@ import kotlin.math.round
.shortName(R.string.medtrum_pump_shortname)
.preferencesId(R.xml.pref_medtrum_pump)
.description(R.string.medtrum_pump_description), injector, aapsLogger, rh, commandQueue
-), Pump {
+), Pump, Medtrum {
private val disposable = CompositeDisposable()
private var medtrumService: MedtrumService? = null
@@ -270,16 +271,20 @@ import kotlin.math.round
// round rate to pump rate
val pumpRate = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value()
temporaryBasalStorage.add(PumpSync.PumpState.TemporaryBasal(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), pumpRate, true, tbrType, 0L, 0L))
- val connectionOk = medtrumService?.setTempBasal(pumpRate, durationInMinutes) ?: false
- if (connectionOk
- && medtrumPump.tempBasalInProgress
+ val connectionOK = medtrumService?.setTempBasal(pumpRate, durationInMinutes) ?: false
+ if (connectionOK
+ && medtrumPump.tempBasalInProgress
&& Math.abs(medtrumPump.tempBasalAbsoluteRate - pumpRate) <= 0.05
- /*&& Math.abs(medtrumPump.tempBasalRemainingMinutes - durationInMinutes) <= 5*/) {
-
- return PumpEnactResult(injector).success(true).enacted(true).duration(/*medtrumPump.tempBasalRemainingMinutes*/durationInMinutes).absolute(medtrumPump.tempBasalAbsoluteRate).isPercent(false)
+ /*&& Math.abs(medtrumPump.tempBasalRemainingMinutes - durationInMinutes) <= 5*/) {
+
+ return PumpEnactResult(injector).success(true).enacted(true).duration(/*medtrumPump.tempBasalRemainingMinutes*/durationInMinutes).absolute(medtrumPump.tempBasalAbsoluteRate)
+ .isPercent(false)
.isTempCancel(false)
} else {
- aapsLogger.error(LTag.PUMP, "setTempBasalAbsolute failed, connectionOk: $connectionOk, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}, tempBasalAbsoluteRate: ${medtrumPump.tempBasalAbsoluteRate}") //, tempBasalRemainingMinutes: ${medtrumPump.tempBasalRemainingMinutes}")
+ aapsLogger.error(
+ LTag.PUMP,
+ "setTempBasalAbsolute failed, connectionOK: $connectionOK, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}, tempBasalAbsoluteRate: ${medtrumPump.tempBasalAbsoluteRate}"
+ ) //, tempBasalRemainingMinutes: ${medtrumPump.tempBasalRemainingMinutes}")
return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum setTempBasalAbsolute failed")
}
}
@@ -298,11 +303,11 @@ import kotlin.math.round
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
aapsLogger.info(LTag.PUMP, "cancelTempBasal - enforceNew: $enforceNew")
- val connectionOk = medtrumService?.cancelTempBasal() ?: false
- if (connectionOk && !medtrumPump.tempBasalInProgress) {
+ val connectionOK = medtrumService?.cancelTempBasal() ?: false
+ if (connectionOK && !medtrumPump.tempBasalInProgress) {
return PumpEnactResult(injector).success(true).enacted(true).isTempCancel(true)
} else {
- aapsLogger.error(LTag.PUMP, "cancelTempBasal failed, connectionOk: $connectionOk, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}")
+ aapsLogger.error(LTag.PUMP, "cancelTempBasal failed, connectionOK: $connectionOK, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}")
return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum cancelTempBasal failed")
}
}
@@ -357,4 +362,15 @@ import kotlin.math.round
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
}
+
+ // Medtrum interface
+ override fun loadEvents(): PumpEnactResult {
+ if (!isInitialized()) {
+ val result = PumpEnactResult(injector).success(false)
+ result.comment = "pump not initialized"
+ return result
+ }
+ val connectionOK = medtrumService?.loadEvents() ?: false
+ return PumpEnactResult(injector).success(connectionOK)
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
index 3503c4a0fe..c3067ed501 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
@@ -48,16 +48,19 @@ class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(inject
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
- pumpSync.syncStopTemporaryBasalWithPumpId(
- timestamp = basalStartTime, // Time of normal basal start = time of tbr end
- endPumpId = basalStartTime,
- pumpType = medtrumPump.pumpType,
- pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
- )
- aapsLogger.warn(
- LTag.PUMPCOMM,
- "CancelTempBasalPacket: EVENT TEMP_END ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) "
- )
+ if (basalType == BasalType.STANDARD) {
+ // If we have standard here, means TBR is cancelled successfully
+ pumpSync.syncStopTemporaryBasalWithPumpId(
+ timestamp = basalStartTime, // Time of normal basal start = time of tbr end
+ endPumpId = basalStartTime,
+ pumpType = medtrumPump.pumpType,
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "CancelTempBasalPacket: EVENT TEMP_END ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) "
+ )
+ }
}
return success
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
index e2c80fe7dc..4df32dafe7 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SynchronizePacket.kt
@@ -55,12 +55,12 @@ class SynchronizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector)
offset += 4 // If field is present, skip 4 bytes
}
if (fieldMask and MASK_NORMAL_BOLUS != 0) {
- aapsLogger.warn(LTag.PUMPCOMM, "SynchronizePacket: Normal bolus present removing from fieldMask")
+ aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: Normal bolus present removing from fieldMask")
fieldMask = fieldMask and MASK_NORMAL_BOLUS.inv()
syncData = syncData.copyOfRange(0, offset) + syncData.copyOfRange(offset + 3, syncData.size)
}
if (fieldMask and MASK_EXTENDED_BOLUS != 0) {
- aapsLogger.warn(LTag.PUMPCOMM, "SynchronizePacket: Extended bolus present removing from fieldMask")
+ aapsLogger.debug(LTag.PUMPCOMM, "SynchronizePacket: Extended bolus present removing from fieldMask")
fieldMask = fieldMask and MASK_EXTENDED_BOLUS.inv()
syncData = syncData.copyOfRange(0, offset) + syncData.copyOfRange(offset + 3, syncData.size)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index c934a84ccf..fe62dfe767 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -72,7 +72,7 @@ class BLEComm @Inject internal constructor(
companion object {
- private const val WRITE_DELAY_MILLIS: Long = 50
+ private const val WRITE_DELAY_MILLIS: Long = 100
private const val SERVICE_UUID = "669A9001-0008-968F-E311-6050405558B3"
private const val READ_UUID = "669a9120-0008-968f-e311-6050405558b3"
private const val WRITE_UUID = "669a9101-0008-968f-e311-6050405558b3"
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 3742448a25..2bf9de608b 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -72,7 +72,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
companion object {
- // TODO: Test and further increase?
private const val COMMAND_DEFAULT_TIMEOUT_SEC: Long = 60
private const val COMMAND_SYNC_TIMEOUT_SEC: Long = 120
private const val COMMAND_CONNECTING_TIMEOUT_SEC: Long = 30
@@ -198,9 +197,12 @@ class MedtrumService : DaggerService(), BLECommCallback {
bleComm.disconnect(from)
}
- fun readPumpStatus() {
- // Most of these things are already done when a connection is setup, but wo dont know how long the pump was connected for?
+ fun readPumpStatus() {
+ // Update pump events
+ loadEvents()
+ }
+ fun loadEvents(): Boolean {
// Send a poll patch, to workaround connection losses?
var result = sendPacketAndGetResponse(PollPatchPacket(injector))
// So just do a syncronize to make sure we have the latest data
@@ -210,9 +212,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
if (result) result = syncRecords()
if (!result) {
aapsLogger.error(LTag.PUMPCOMM, "Failed to sync records")
- return
}
if (result) medtrumPump.lastConnection = System.currentTimeMillis()
+ aapsLogger.debug(LTag.PUMPCOMM, "Events loaded")
+ rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingpumpstatus)))
+ return result
}
fun setBolus(insulin: Double, t: EventOverviewBolusProgress.Treatment): Boolean {
@@ -250,13 +254,19 @@ class MedtrumService : DaggerService(), BLECommCallback {
val bolusDurationInMSec = (insulin * 60 * 1000)
val expectedEnd = bolusStart + bolusDurationInMSec + 2000
- while (System.currentTimeMillis() < expectedEnd && result == true) {
+ while (System.currentTimeMillis() < expectedEnd && result == true && medtrumPump.bolusDone == false) {
SystemClock.sleep(1000)
}
// Do not call update status directly, reconnection may be needed
- commandQueue.readStatus(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus), object : Callback() {
+ commandQueue.loadEvents(object : Callback() {
override fun run() {
+ if (this.result.success == false && isConnected == false) {
+ // Reschedule loadEvents when we lost connection during the command
+ aapsLogger.warn(LTag.PUMP, "loadEvents failed due to connection loss, rescheduling")
+ commandQueue.loadEvents(this)
+ return
+ }
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus)))
bolusingEvent.percent = 100
}
@@ -278,7 +288,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Get history records, this will update the prevoius basals
// Do not call update status directly, reconnection may be needed
- commandQueue.readStatus(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus), object : Callback() {
+ commandQueue.loadEvents(object : Callback() {
override fun run() {
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus)))
}
@@ -292,7 +302,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Get history records, this will update the prevoius basals
// Do not call update status directly, reconnection may be needed
- commandQueue.readStatus(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus), object : Callback() {
+ commandQueue.loadEvents(object : Callback() {
override fun run() {
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingtempbasalstatus)))
}
@@ -312,7 +322,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
if (result) result = packet?.let { sendPacketAndGetResponse(it) } == true
// Get history records, this will update the pump state and add changes in TBR to AAPS history
- if (result) result = syncRecords()
+ commandQueue.loadEvents(null)
return result
}
@@ -690,9 +700,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
override fun onEnter() {
aapsLogger.debug(LTag.PUMPCOMM, "Medtrum Service reached ReadyState!")
// Now we are fully connected and authenticated and we can start sending commands. Let AAPS know
- medtrumPump.connectionState = ConnectionState.CONNECTED
- if (medtrumPlugin.isInitialized()) {
- rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
+ if (isConnected == false) {
+ medtrumPump.connectionState = ConnectionState.CONNECTED
+ if (medtrumPlugin.isInitialized()) {
+ rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
+ }
}
}
}
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index f665fc5dfe..2e0e041f14 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -46,7 +46,9 @@
SN
Serial number pump base
+
Waiting for bolus end. Remaining %1$d sec.
+ Getting pump status
Getting bolus status
Getting temporary basal status
From 419def7f6b89253cf92efb081a298a35e087625c Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 13 Jun 2023 13:35:08 +0200
Subject: [PATCH 038/116] Notifications and fake TBR on state changes
---
.../interfaces/notifications/Notification.kt | 3 +-
.../nightscout/pump/combov2/ComboV2Plugin.kt | 2 +-
.../nightscout/pump/medtrum/MedtrumPump.kt | 65 +++++++++++--------
.../pump/medtrum/services/BLEComm.kt | 7 +-
.../pump/medtrum/services/MedtrumService.kt | 50 ++++++++++----
pump/medtrum/src/main/res/values/strings.xml | 3 +-
6 files changed, 86 insertions(+), 44 deletions(-)
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt
index 066e412c5f..51989bbaa7 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt
@@ -131,9 +131,10 @@ open class Notification {
const val IDENTIFICATION_NOT_SET = 77
const val PERMISSION_BT = 78
const val EOELOW_PATCH_ALERTS = 79
- const val COMBO_PUMP_SUSPENDED = 80
+ const val PUMP_SUSPENDED = 80
const val COMBO_UNKNOWN_TBR = 81
const val BLUETOOTH_NOT_ENABLED = 82
+ const val PATCH_NOT_ACTIVE = 83
const val USER_MESSAGE = 1000
diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt
index fd853783a1..d2bbe87b7f 100644
--- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt
+++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt
@@ -2216,7 +2216,7 @@ class ComboV2Plugin @Inject constructor (
// only shows up in the Combo fragment.
if (newState == DriverState.Suspended) {
uiInteraction.addNotification(
- Notification.COMBO_PUMP_SUSPENDED,
+ Notification.PUMP_SUSPENDED,
text = rh.gs(R.string.combov2_pump_is_suspended),
level = Notification.NORMAL
)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index d2d2d28611..6fa1677ced 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -33,6 +33,11 @@ class MedtrumPump @Inject constructor(
private val temporaryBasalStorage: TemporaryBasalStorage
) {
+ companion object {
+
+ const val FAKE_TBR_LENGTH = 4800L
+ }
+
// Connection state flow
private val _connectionState = MutableStateFlow(ConnectionState.DISCONNECTED)
val connectionStateFlow: StateFlow = _connectionState
@@ -42,7 +47,6 @@ class MedtrumPump @Inject constructor(
_connectionState.value = value
}
-
// Pump state flow
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
val pumpStateFlow: StateFlow = _pumpState
@@ -61,15 +65,15 @@ class MedtrumPump @Inject constructor(
set(value) {
_primeProgress.value = value
}
-
+
private var _lastBasalType: MutableStateFlow = MutableStateFlow(BasalType.NONE)
val lastBasalTypeFlow: StateFlow = _lastBasalType
var lastBasalType: BasalType
get() = _lastBasalType.value
set(value) {
_lastBasalType.value = value
- }
-
+ }
+
private val _lastBasalRate = MutableStateFlow(0.0)
val lastBasalRateFlow: StateFlow = _lastBasalRate
var lastBasalRate: Double
@@ -85,7 +89,7 @@ class MedtrumPump @Inject constructor(
set(value) {
_reservoir.value = value
}
-
+
/** Stuff stored in SP */
private var _patchSessionToken = 0L
var patchSessionToken: Long
@@ -125,7 +129,7 @@ class MedtrumPump @Inject constructor(
set(value) {
_actualBasalProfile = value
val encodedString = Base64.encodeToString(value, Base64.DEFAULT)
- sp.putString(R.string.key_actual_basal_profile, encodedString?: "")
+ sp.putString(R.string.key_actual_basal_profile, encodedString ?: "")
}
private var _pumpSN = 0L
@@ -140,7 +144,6 @@ class MedtrumPump @Inject constructor(
var patchStartTime = 0L // Time in ms!
var patchAge = 0L // Time in seconds?! // TODO: Not used
-
var batteryVoltage_A = 0.0
var batteryVoltage_B = 0.0
@@ -276,7 +279,7 @@ class MedtrumPump @Inject constructor(
bolusDone = true
bolusingTreatment?.insulin = amountDelivered
} else {
- bolusingTreatment?.insulin = amountDelivered
+ bolusingTreatment?.insulin = amountDelivered
}
}
@@ -292,7 +295,7 @@ class MedtrumPump @Inject constructor(
val temporaryBasalInfo = temporaryBasalStorage.findTemporaryBasal(basalStartTime, basalRate)
// If duration is unknown, no way to get it now, set patch lifetime as duration
- val duration = temporaryBasalInfo?.duration ?: T.mins(4800).msecs()
+ val duration = temporaryBasalInfo?.duration ?: T.mins(FAKE_TBR_LENGTH).msecs()
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime,
rate = basalRate, // TODO: Support percent here, this will break things? Check if this is correct
@@ -311,7 +314,7 @@ class MedtrumPump @Inject constructor(
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime,
rate = 0.0,
- duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER
+ duration = T.mins(FAKE_TBR_LENGTH).msecs(),
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime,
@@ -322,23 +325,9 @@ class MedtrumPump @Inject constructor(
LTag.PUMPCOMM,
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) expectedTemporaryBasal: $expectedTemporaryBasal"
)
- } else if (basalType == BasalType.NONE && expectedTemporaryBasal?.rate != basalRate && expectedTemporaryBasal?.duration != T.mins(4800).msecs()) {
+ } else if (basalType == BasalType.NONE && expectedTemporaryBasal?.rate != basalRate && expectedTemporaryBasal?.duration != T.mins(FAKE_TBR_LENGTH).msecs()) {
// Pump suspended, set fake TBR
- // TODO: Maybe move this to separate function?
- val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
- timestamp = dateUtil.now(),
- rate = basalRate,
- duration = T.mins(4800).msecs(), // TODO MAGIC NUMBER
- isAbsolute = true,
- type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
- pumpId = dateUtil.now(),
- pumpType = pumpType,
- pumpSerial = pumpSN.toString(radix = 16)
- )
- aapsLogger.debug(
- LTag.PUMPCOMM,
- "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) expectedTemporaryBasal: $expectedTemporaryBasal"
- )
+ setFakeTBR()
}
// Update medtrum pump state
@@ -366,4 +355,28 @@ class MedtrumPump @Inject constructor(
aapsLogger.error(LTag.PUMP, "handleStopStatusUpdate: WTF? PatchId in status update does not match current patchId!")
}
}
+
+ fun setFakeTBRIfNeeded() {
+ val expectedTemporaryBasal = pumpSync.expectedPumpState().temporaryBasal
+ if (expectedTemporaryBasal?.rate != 0.0 && expectedTemporaryBasal?.duration != T.mins(FAKE_TBR_LENGTH).msecs()) {
+ setFakeTBR()
+ }
+ }
+
+ private fun setFakeTBR() {
+ val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
+ timestamp = dateUtil.now(),
+ rate = 0.0,
+ duration = T.mins(FAKE_TBR_LENGTH).msecs(),
+ isAbsolute = true,
+ type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
+ pumpId = dateUtil.now(),
+ pumpType = pumpType,
+ pumpSerial = pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START (FAKE)"
+ )
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index fe62dfe767..8a72ae691c 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -177,8 +177,7 @@ class BLEComm @Inject internal constructor(
// Reset sequence counter
mWriteSequenceNumber = 0
if (mBluetoothGatt == null) {
- mBluetoothGatt =
- device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
+ mBluetoothGatt = device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
} else {
// Already connected?, this should not happen force disconnect
aapsLogger.error(LTag.PUMPBTCOMM, "connectGatt, mBluetoothGatt is not null")
@@ -200,7 +199,7 @@ class BLEComm @Inject internal constructor(
isConnecting = false
stopScan()
SystemClock.sleep(100)
- }
+ }
if (isConnected) {
aapsLogger.debug(LTag.PUMPBTCOMM, "Connected, disconnecting")
mBluetoothGatt?.disconnect()
@@ -402,7 +401,7 @@ class BLEComm @Inject internal constructor(
aapsLogger.warn(LTag.PUMPBTCOMM, "Disconnected while connecting! Reset device address")
mDevice = null
// Wait a bit before retrying
- SystemClock.sleep(2000)
+ SystemClock.sleep(2000)
}
close()
isConnected = false
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 2bf9de608b..80ddda49f8 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -110,13 +110,46 @@ class MedtrumService : DaggerService(), BLECommCallback {
scope.launch {
medtrumPump.pumpStateFlow.collect { state ->
when (state) {
+ MedtrumPumpState.NONE,
+ MedtrumPumpState.IDLE,
+ MedtrumPumpState.FILLED,
+ MedtrumPumpState.PRIMING,
+ MedtrumPumpState.PRIMED,
+ MedtrumPumpState.EJECTING,
+ MedtrumPumpState.EJECTED,
+ MedtrumPumpState.STOPPED -> {
+ rxBus.send(EventDismissNotification(Notification.PUMP_ERROR))
+ rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
+ uiInteraction.addNotification(
+ Notification.PATCH_NOT_ACTIVE,
+ rh.gs(R.string.patch_not_active),
+ Notification.URGENT,
+ )
+ medtrumPump.setFakeTBRIfNeeded()
+ }
+
+ MedtrumPumpState.ACTIVE,
+ MedtrumPumpState.ACTIVE_ALT -> {
+ rxBus.send(EventDismissNotification(Notification.PATCH_NOT_ACTIVE))
+ rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
+ }
+
MedtrumPumpState.LOWBG_SUSPENDED,
MedtrumPumpState.LOWBG_SUSPENDED2,
MedtrumPumpState.AUTO_SUSPENDED,
MedtrumPumpState.HMAX_SUSPENDED,
MedtrumPumpState.DMAX_SUSPENDED,
MedtrumPumpState.SUSPENDED,
- MedtrumPumpState.PAUSED,
+ MedtrumPumpState.PAUSED -> {
+ // TODO: Message with reason
+ uiInteraction.addNotification(
+ Notification.PUMP_SUSPENDED,
+ rh.gs(R.string.pump_is_suspended),
+ Notification.NORMAL,
+ )
+ // Pump will report proper TBR for this
+ }
+
MedtrumPumpState.OCCLUSION,
MedtrumPumpState.EXPIRED,
MedtrumPumpState.RESERVOIR_EMPTY,
@@ -125,21 +158,16 @@ class MedtrumService : DaggerService(), BLECommCallback {
MedtrumPumpState.BASE_FAULT,
MedtrumPumpState.BATTERY_OUT,
MedtrumPumpState.NO_CALIBRATION -> {
- // Pump suspended show error!
+ rxBus.send(EventDismissNotification(Notification.PATCH_NOT_ACTIVE))
+ rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
+ // Pump suspended due to error, show error!
uiInteraction.addNotificationWithSound(
Notification.PUMP_ERROR,
rh.gs(R.string.pump_error, state.toString()),
Notification.URGENT,
info.nightscout.core.ui.R.raw.alarm
)
- }
-
- MedtrumPumpState.STOPPED -> {
- rxBus.send(EventDismissNotification(Notification.PUMP_ERROR))
- }
-
- else -> {
- // Do nothing
+ medtrumPump.setFakeTBRIfNeeded()
}
}
}
@@ -197,7 +225,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
bleComm.disconnect(from)
}
- fun readPumpStatus() {
+ fun readPumpStatus() {
// Update pump events
loadEvents()
}
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 2e0e041f14..8049096766 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -15,6 +15,8 @@
Medtrum Nano
Medtrum pump settings
Pump error: %1$s !!
+ Pump is suspended
+ Patch not activated
BLE Status
@@ -52,5 +54,4 @@
Getting bolus status
Getting temporary basal status
-
From 49de6a9c3242be12b66da79fea9bcfd07c1265d8 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 13 Jun 2023 21:42:05 +0200
Subject: [PATCH 039/116] Add settings, and setting sync with pump
---
.../interfaces/notifications/Notification.kt | 1 +
.../nightscout/interfaces/pump/Medtrum.kt | 1 +
.../queue/commands/CommandSetUserSettings.kt | 7 +++
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 10 ++++
.../nightscout/pump/medtrum/MedtrumPump.kt | 17 ++++---
.../medtrum/comm/packets/ActivatePacket.kt | 2 +-
.../medtrum/comm/packets/SetPatchPacket.kt | 14 ++++--
.../pump/medtrum/services/MedtrumService.kt | 38 +++++++++++----
.../medtrum/ui/viewmodel/MedtrumViewModel.kt | 1 +
pump/medtrum/src/main/res/values/arrays.xml | 23 +++++++++
pump/medtrum/src/main/res/values/strings.xml | 21 +++++++--
.../src/main/res/xml/pref_medtrum_pump.xml | 47 ++++++++++++++++---
.../comm/packets/ActivatePacketTest.kt | 4 +-
.../comm/packets/SetPatchPacketTest.kt | 4 +-
14 files changed, 153 insertions(+), 37 deletions(-)
create mode 100644 pump/medtrum/src/main/res/values/arrays.xml
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt
index 51989bbaa7..24f55d074e 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt
@@ -135,6 +135,7 @@ open class Notification {
const val COMBO_UNKNOWN_TBR = 81
const val BLUETOOTH_NOT_ENABLED = 82
const val PATCH_NOT_ACTIVE = 83
+ const val PUMP_SETTINGS_FAILED = 84
const val USER_MESSAGE = 1000
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
index d17e58d45f..7ae90a7b01 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
@@ -6,4 +6,5 @@ package info.nightscout.interfaces.pump
interface Medtrum {
fun loadEvents(): PumpEnactResult // events history to build treatments from
+ fun setUserOptions(): PumpEnactResult // set user settings
}
\ No newline at end of file
diff --git a/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandSetUserSettings.kt b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandSetUserSettings.kt
index 471c83c670..cb120cf32a 100644
--- a/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandSetUserSettings.kt
+++ b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandSetUserSettings.kt
@@ -4,6 +4,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.pump.Dana
import info.nightscout.interfaces.pump.Diaconn
+import info.nightscout.interfaces.pump.Medtrum
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.queue.Callback
import info.nightscout.interfaces.queue.Command
@@ -30,6 +31,12 @@ class CommandSetUserSettings(
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
callback?.result(r)?.run()
}
+
+ if (pump is Medtrum) {
+ val r = pump.setUserOptions()
+ aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
+ callback?.result(r)?.run()
+ }
}
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.set_user_settings)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index bfef4fa928..2b66931397 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -373,4 +373,14 @@ import kotlin.math.round
val connectionOK = medtrumService?.loadEvents() ?: false
return PumpEnactResult(injector).success(connectionOK)
}
+
+ override fun setUserOptions(): PumpEnactResult {
+ if (!isInitialized()) {
+ val result = PumpEnactResult(injector).success(false)
+ result.comment = "pump not initialized"
+ return result
+ }
+ val connectionOK = medtrumService?.setUserSettings() ?: false
+ return PumpEnactResult(injector).success(connectionOK)
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 6fa1677ced..f069dbea00 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -177,14 +177,13 @@ class MedtrumPump @Inject constructor(
var lastStopSequence = 0
var lastStopPatchId = 0L
- // TODO set these setting on init
// User settings (desired values, to be set on pump)
var desiredPatchExpiration = false
- var desiredAlarmSetting = AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code
+ var desiredAlarmSetting = AlarmSetting.LIGHT_VIBRATE_AND_BEEP
var desiredHourlyMaxInsulin: Int = 40
var desiredDailyMaxInsulin: Int = 180
- init {
+ fun loadFromSP() {
// Load stuff from SP
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
@@ -203,14 +202,14 @@ class MedtrumPump @Inject constructor(
}
fun loadUserSettingsFromSP() {
- // TODO
- // desiredPatchExpiration = sp.getBoolean(R.string.key_patch_expiration, false)
- // desiredAlarmSetting = sp.getInt(R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code)
- // desiredHourlyMaxInsulin = sp.getInt(R.string.key_hourly_max_insulin, 40)
- // desiredDailyMaxInsulin = sp.getInt(R.string.key_daily_max_insulin, 180)
+ desiredPatchExpiration = sp.getBoolean(info.nightscout.pump.medtrum.R.string.key_patch_expiration, false)
+ val alarmSettingCode = sp.getString(info.nightscout.pump.medtrum.R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code.toString())?.toByte()
+ desiredAlarmSetting = AlarmSetting.values().firstOrNull { it.code == alarmSettingCode } ?: AlarmSetting.LIGHT_VIBRATE_AND_BEEP
+ desiredHourlyMaxInsulin = sp.getInt(info.nightscout.pump.medtrum.R.string.key_hourly_max_insulin, 40)
+ desiredDailyMaxInsulin = sp.getInt(info.nightscout.pump.medtrum.R.string.key_daily_max_insulin, 180)
try {
- _pumpSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_snInput, " ").toLong(radix = 16)
+ _pumpSN = sp.getString(info.nightscout.pump.medtrum.R.string.key_sn_input, " ").toLong(radix = 16)
} catch (e: NumberFormatException) {
aapsLogger.debug(LTag.PUMP, "changePump: Invalid input!")
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
index f18998d186..2eaeb17b86 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
@@ -65,7 +65,7 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
val autoSuspendTime: Byte = 12 // Not sure why, but pump needs this in order to activate
val patchExpiration: Byte = medtrumPump.desiredPatchExpiration.toByte()
- val alarmSetting: Byte = medtrumPump.desiredAlarmSetting
+ val alarmSetting: Byte = medtrumPump.desiredAlarmSetting.code
val lowSuspend: Byte = 0
val predictiveLowSuspend: Byte = 0
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
index fad3171614..c9196f5bee 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacket.kt
@@ -2,6 +2,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_PATCH
import info.nightscout.pump.medtrum.extension.toByte
import info.nightscout.pump.medtrum.extension.toByteArray
@@ -20,8 +21,8 @@ class SetPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
/**
* byte 0: opCode
* byte 1: alarmSetting // See AlarmSetting
- * byte 2-3: hourlyMaxInsulin // Max hourly dose of insulin not used for now, divided by 0.05
- * byte 4-5: dailyMaxSet // Max daily dose of insulin not used for now, divided by 0.05
+ * byte 2-3: hourlyMaxInsulin // Max hourly dose of insulin, divided by 0.05
+ * byte 4-5: dailyMaxSet // Max daily dose of insulin, divided by 0.05
* byte 6: expirationTimer // Expiration timer, 0 = no expiration 1 = 12 hour reminder and expiration
* byte 7: autoSuspendEnable // Value for auto mode, not used for AAPS
* byte 8: autoSuspendTime // Value for auto mode, not used for AAPS
@@ -30,11 +31,16 @@ class SetPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
* byte 11: predictiveLowSuspendRange // Value for auto mode, not used for AAPS
*/
- val alarmSetting: Byte = medtrumPump.desiredAlarmSetting
+ val alarmSetting: AlarmSetting = medtrumPump.desiredAlarmSetting
val hourlyMaxInsulin: Int = round(medtrumPump.desiredHourlyMaxInsulin / 0.05).toInt()
val dailyMaxInsulin: Int = round(medtrumPump.desiredDailyMaxInsulin / 0.05).toInt()
val patchExpiration: Byte = medtrumPump.desiredPatchExpiration.toByte()
+ val autoSuspendEnable: Byte = 0
+ val autoSuspendTime: Byte = 12 // Not sure why, but pump needs this
+ val lowSuspend: Byte = 0
+ val predictiveLowSuspend: Byte = 0
+ val predictiveLowSuspendRange: Byte = 30 // Not sure why, but pump needs this
- return byteArrayOf(opCode) + alarmSetting + hourlyMaxInsulin.toByteArray(2) + dailyMaxInsulin.toByteArray(2) + patchExpiration + 0.toByteArray(5)
+ return byteArrayOf(opCode) + alarmSetting.code + hourlyMaxInsulin.toByteArray(2) + dailyMaxInsulin.toByteArray(2) + patchExpiration + autoSuspendEnable + autoSuspendTime + lowSuspend + predictiveLowSuspend + predictiveLowSuspendRange
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 80ddda49f8..659c3b397c 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -103,8 +103,26 @@ class MedtrumService : DaggerService(), BLECommCallback {
.toObservable(EventPreferenceChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event ->
- if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_snInput))) {
- changePump()
+ if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_sn_input))) {
+ medtrumPump.loadUserSettingsFromSP()
+ }
+ if (event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_alarm_setting))
+ || event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_patch_expiration))
+ || event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_hourly_max_insulin))
+ || event.isChanged(rh.gs(info.nightscout.pump.medtrum.R.string.key_daily_max_insulin))
+ ) {
+ medtrumPump.loadUserSettingsFromSP()
+ commandQueue.setUserOptions(object : Callback() {
+ override fun run() {
+ if (medtrumPlugin.isInitialized() && this.result.success == false) {
+ uiInteraction.addNotification(
+ Notification.PUMP_SETTINGS_FAILED,
+ rh.gs(R.string.pump_setting_failed),
+ Notification.NORMAL,
+ )
+ }
+ }
+ })
}
}, fabricPrivacy::logException)
scope.launch {
@@ -173,7 +191,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
- changePump()
+ medtrumPump.loadFromSP()
}
override fun onDestroy() {
@@ -247,6 +265,11 @@ class MedtrumService : DaggerService(), BLECommCallback {
return result
}
+ fun setUserSettings(): Boolean {
+ rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.settingpumpsettings)))
+ return sendPacketAndGetResponse(SetPatchPacket(injector))
+ }
+
fun setBolus(insulin: Double, t: EventOverviewBolusProgress.Treatment): Boolean {
if (!isConnected) return false
val result = sendPacketAndGetResponse(SetBolusPacket(injector, insulin))
@@ -314,7 +337,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
if (result) result = sendPacketAndGetResponse(SetTempBasalPacket(injector, absoluteRate, durationInMinutes))
- // Get history records, this will update the prevoius basals
+ // Get history records, this will update the prevoius basals
// Do not call update status directly, reconnection may be needed
commandQueue.loadEvents(object : Callback() {
override fun run() {
@@ -328,7 +351,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun cancelTempBasal(): Boolean {
var result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
- // Get history records, this will update the prevoius basals
+ // Get history records, this will update the prevoius basals
// Do not call update status directly, reconnection may be needed
commandQueue.loadEvents(object : Callback() {
override fun run() {
@@ -355,11 +378,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
return result
}
- fun changePump() {
- aapsLogger.debug(LTag.PUMP, "changePump: called!")
- medtrumPump.loadUserSettingsFromSP()
- }
-
/** This gets the history records from the pump */
private fun syncRecords(): Boolean {
aapsLogger.debug(LTag.PUMP, "syncRecords: called!, syncedSequenceNumber: ${medtrumPump.syncedSequenceNumber}, currentSequenceNumber: ${medtrumPump.currentSequenceNumber}")
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
index 873e674116..01fb12016a 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumViewModel.kt
@@ -67,6 +67,7 @@ class MedtrumViewModel @Inject constructor(
if (patchStep.value == PatchStep.START_DEACTIVATION) {
updateSetupStep(SetupStep.READY_DEACTIVATE)
}
+ medtrumPump.lastConnection = System.currentTimeMillis()
}
ConnectionState.DISCONNECTED -> {
diff --git a/pump/medtrum/src/main/res/values/arrays.xml b/pump/medtrum/src/main/res/values/arrays.xml
new file mode 100644
index 0000000000..f2184b0875
--- /dev/null
+++ b/pump/medtrum/src/main/res/values/arrays.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+ - Vibrate and beep
+ - Vibrate only
+ - Beep only
+ - None
+
+
+
+
+
+
+ - 4
+ - 5
+ - 6
+ - 7
+
+
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 8049096766..958da20f9d 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -1,7 +1,12 @@
- snInput
+ sn_input
+ alarm_setting
+ patch_expiration
+ hourly_max_insulin
+ daily_max_insulin
+
medtrumpump_settings
pump_state
medtrum_session_token
@@ -17,6 +22,7 @@
Pump error: %1$s !!
Pump is suspended
Patch not activated
+ Setting user settings to pump failed!
BLE Status
@@ -45,13 +51,22 @@
Deactivation
- SN
- Serial number pump base
+ Serial Number
+ Enter the serial number of your pump base.
+ Alarm Settings
+ Select your preferred pump alarm settings.
+ Patch Expiration
+ Turn this on to get an alert 12 hours before the patch expiration. When enabled, the patch will expire after 3 days.
+ Hourly Maximum Insulin
+ Specify the maximum units of insulin allowed per hour. If exceeded, the pump will suspend.
+ Daily Maximum Insulin
+ Specify the maximum units of insulin allowed per day. If exceeded, the pump will suspend.
Waiting for bolus end. Remaining %1$d sec.
Getting pump status
Getting bolus status
Getting temporary basal status
+ Setting user options
diff --git a/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml b/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
index 9b40fc9864..c87d2384d2 100644
--- a/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
+++ b/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
@@ -1,6 +1,6 @@
-
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:validate="http://schemas.android.com/apk/res-auto">
+ android:title="@string/sn_input_title" />
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
index 7a29b2e516..56c82c95a4 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacketTest.kt
@@ -26,7 +26,7 @@ class ActivatePacketTest : MedtrumTestBase() {
@Test fun getRequestGivenPacketWhenValuesSetThenReturnCorrectByteArray() {
// Inputs
medtrumPump.desiredPatchExpiration = true
- medtrumPump.desiredAlarmSetting = AlarmSetting.BEEP_ONLY.code
+ medtrumPump.desiredAlarmSetting = AlarmSetting.BEEP_ONLY
medtrumPump.desiredDailyMaxInsulin = 40
medtrumPump.desiredDailyMaxInsulin = 180
@@ -44,7 +44,7 @@ class ActivatePacketTest : MedtrumTestBase() {
@Test fun handleResponseGivenPacketWhenValuesSetThenReturnCorrectValues() {
// Inputs
medtrumPump.desiredPatchExpiration = true
- medtrumPump.desiredAlarmSetting = AlarmSetting.BEEP_ONLY.code
+ medtrumPump.desiredAlarmSetting = AlarmSetting.BEEP_ONLY
medtrumPump.desiredDailyMaxInsulin = 40
medtrumPump.desiredDailyMaxInsulin = 180
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
index eb15c6f032..80bdf591fd 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/SetPatchPacketTest.kt
@@ -23,7 +23,7 @@ class SetPatchPacketTest : MedtrumTestBase() {
@Test fun getRequestGivenValuesWhenCalledThenReturnValidArray() {
// Inputs
medtrumPump.desiredPatchExpiration = false
- medtrumPump.desiredAlarmSetting = AlarmSetting.LIGHT_AND_VIBRATE.code
+ medtrumPump.desiredAlarmSetting = AlarmSetting.LIGHT_AND_VIBRATE
medtrumPump.desiredDailyMaxInsulin = 40
medtrumPump.desiredDailyMaxInsulin = 180
@@ -32,7 +32,7 @@ class SetPatchPacketTest : MedtrumTestBase() {
val result = packet.getRequest()
// Expected values
- val expected = byteArrayOf(35, 1, 32, 3, 16, 14, 0, 0, 0, 0, 0, 0)
+ val expected = byteArrayOf(35, 1, 32, 3, 16, 14, 0, 0, 12, 0, 0, 30)
assertEquals(expected.contentToString(), result.contentToString())
}
}
From 3a33f46e2fbb6986cc835b4aced4376835a35111 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 15 Jun 2023 18:52:55 +0200
Subject: [PATCH 040/116] Fix wrong notifications, and error on load
---
.../src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt | 4 +---
.../info/nightscout/pump/medtrum/services/MedtrumService.kt | 2 +-
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index f069dbea00..d6f46b2fea 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -183,7 +183,7 @@ class MedtrumPump @Inject constructor(
var desiredHourlyMaxInsulin: Int = 40
var desiredDailyMaxInsulin: Int = 180
- fun loadFromSP() {
+ init {
// Load stuff from SP
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
@@ -197,8 +197,6 @@ class MedtrumPump @Inject constructor(
} catch (e: Exception) {
aapsLogger.error(LTag.PUMP, "Error decoding basal profile from SP: $encodedString")
}
-
- loadUserSettingsFromSP()
}
fun loadUserSettingsFromSP() {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 659c3b397c..1f6a836c89 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -191,7 +191,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
- medtrumPump.loadFromSP()
+ medtrumPump.loadUserSettingsFromSP()
}
override fun onDestroy() {
From 7b536309470d3f357884cca136f0568bba0ef0c7 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 15 Jun 2023 20:17:45 +0200
Subject: [PATCH 041/116] Add Clear alarms, new overview layout
---
.../nightscout/interfaces/pump/Medtrum.kt | 1 +
.../nightscout/interfaces/queue/Command.kt | 3 +-
.../interfaces/queue/CommandQueue.kt | 1 +
core/ui/src/main/res/values/strings.xml | 1 +
.../implementation/di/CommandQueueModule.kt | 2 +
.../queue/CommandQueueImplementation.kt | 15 +
.../queue/commands/CommandClearAlarms.kt | 39 +
.../queue/CommandQueueImplementationTest.kt | 21 +
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 10 +
.../nightscout/pump/medtrum/code/EventType.kt | 3 +-
.../pump/medtrum/comm/enums/CommandType.kt | 4 +-
.../comm/packets/ClearPumpAlarmPacket.kt | 16 +
.../medtrum/comm/packets/ResumePumpPacket.kt | 16 +
.../pump/medtrum/di/MedtrumCommModule.kt | 4 +
.../pump/medtrum/services/MedtrumService.kt | 61 +-
.../medtrum/ui/MedtrumOverviewFragment.kt | 19 +-
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 105 +--
.../res/layout/fragment_medtrum_overview.xml | 681 ++++++++++++------
pump/medtrum/src/main/res/values/strings.xml | 20 +-
.../comm/packets/ClearPumpAlarmPacketTest.kt | 36 +
.../medtrum/comm/packets/ResumePumpPacket.kt | 33 +
21 files changed, 796 insertions(+), 295 deletions(-)
create mode 100644 implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandClearAlarms.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ClearPumpAlarmPacket.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ResumePumpPacket.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ClearPumpAlarmPacketTest.kt
create mode 100644 pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ResumePumpPacket.kt
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
index 7ae90a7b01..92ebebf2dc 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
@@ -7,4 +7,5 @@ interface Medtrum {
fun loadEvents(): PumpEnactResult // events history to build treatments from
fun setUserOptions(): PumpEnactResult // set user settings
+ fun clearAlarms(): PumpEnactResult // clear alarms
}
\ No newline at end of file
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/queue/Command.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/queue/Command.kt
index 977613aa81..fce81c02bf 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/queue/Command.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/queue/Command.kt
@@ -23,11 +23,12 @@ abstract class Command(
BASAL_PROFILE,
READSTATUS,
LOAD_HISTORY, // TDDs and so far only Dana specific
- LOAD_EVENTS, // so far only Dana specific
+ LOAD_EVENTS,
LOAD_TDD,
SET_USER_SETTINGS, // so far only Dana specific,
START_PUMP,
STOP_PUMP,
+ CLEAR_ALARMS, // so far only Medtrum specific
INSIGHT_SET_TBR_OVER_ALARM, // insight only
CUSTOM_COMMAND
}
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/queue/CommandQueue.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/queue/CommandQueue.kt
index eadf4663db..cbc413d97d 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/queue/CommandQueue.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/queue/CommandQueue.kt
@@ -31,6 +31,7 @@ interface CommandQueue {
fun setUserOptions(callback: Callback?): Boolean
fun loadTDDs(callback: Callback?): Boolean
fun loadEvents(callback: Callback?): Boolean
+ fun clearAlarms(callback: Callback?): Boolean
fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean
fun isCustomCommandRunning(customCommandType: Class): Boolean
fun isCustomCommandInQueue(customCommandType: Class): Boolean
diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml
index f59fd97717..3d27666bf4 100644
--- a/core/ui/src/main/res/values/strings.xml
+++ b/core/ui/src/main/res/values/strings.xml
@@ -393,6 +393,7 @@
CARBS %1$d g
EXTENDED BOLUS %1$.2f U %2$d min
LOAD EVENTS
+ CLEAR_ALARMS
LOAD HISTORY %1$d
LOAD TDDs
SET PROFILE
diff --git a/implementation/src/main/java/info/nightscout/implementation/di/CommandQueueModule.kt b/implementation/src/main/java/info/nightscout/implementation/di/CommandQueueModule.kt
index e6864c9508..0e9a04ba45 100644
--- a/implementation/src/main/java/info/nightscout/implementation/di/CommandQueueModule.kt
+++ b/implementation/src/main/java/info/nightscout/implementation/di/CommandQueueModule.kt
@@ -14,6 +14,7 @@ import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
import info.nightscout.implementation.queue.commands.CommandBolus
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
+import info.nightscout.implementation.queue.commands.CommandClearAlarms
import info.nightscout.implementation.queue.commands.CommandCustomCommand
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
@@ -32,6 +33,7 @@ abstract class CommandQueueModule {
@ContributesAndroidInjector abstract fun commandExtendedBolusInjector(): CommandExtendedBolus
@ContributesAndroidInjector abstract fun commandInsightSetTBROverNotificationInjector(): CommandInsightSetTBROverNotification
@ContributesAndroidInjector abstract fun commandLoadEventsInjector(): CommandLoadEvents
+ @ContributesAndroidInjector abstract fun commandClearAlarmsInjector(): CommandClearAlarms
@ContributesAndroidInjector abstract fun commandLoadHistoryInjector(): CommandLoadHistory
@ContributesAndroidInjector abstract fun commandLoadTDDsInjector(): CommandLoadTDDs
@ContributesAndroidInjector abstract fun commandReadStatusInjector(): CommandReadStatus
diff --git a/implementation/src/main/java/info/nightscout/implementation/queue/CommandQueueImplementation.kt b/implementation/src/main/java/info/nightscout/implementation/queue/CommandQueueImplementation.kt
index 894d7aa308..18cbf76b38 100644
--- a/implementation/src/main/java/info/nightscout/implementation/queue/CommandQueueImplementation.kt
+++ b/implementation/src/main/java/info/nightscout/implementation/queue/CommandQueueImplementation.kt
@@ -22,6 +22,7 @@ import info.nightscout.implementation.R
import info.nightscout.implementation.queue.commands.CommandBolus
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
+import info.nightscout.implementation.queue.commands.CommandClearAlarms
import info.nightscout.implementation.queue.commands.CommandCustomCommand
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
@@ -535,6 +536,20 @@ class CommandQueueImplementation @Inject constructor(
return true
}
+ // returns true if command is queued
+ override fun clearAlarms(callback: Callback?): Boolean {
+ if (isRunning(CommandType.CLEAR_ALARMS)) {
+ callback?.result(executingNowError())?.run()
+ return false
+ }
+ // remove all unfinished
+ removeAll(CommandType.CLEAR_ALARMS)
+ // add new command to queue
+ add(CommandClearAlarms(injector, callback))
+ notifyAboutNewCommand()
+ return true
+ }
+
override fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean {
if (isCustomCommandInQueue(customCommand.javaClass)) {
callback?.result(executingNowError())?.run()
diff --git a/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandClearAlarms.kt b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandClearAlarms.kt
new file mode 100644
index 0000000000..cbfb184d61
--- /dev/null
+++ b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandClearAlarms.kt
@@ -0,0 +1,39 @@
+package info.nightscout.implementation.queue.commands
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.interfaces.plugin.ActivePlugin
+import info.nightscout.interfaces.pump.Dana
+import info.nightscout.interfaces.pump.Diaconn
+import info.nightscout.interfaces.pump.Medtrum
+import info.nightscout.interfaces.pump.PumpEnactResult
+import info.nightscout.interfaces.queue.Callback
+import info.nightscout.interfaces.queue.Command
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class CommandClearAlarms(
+ injector: HasAndroidInjector,
+ callback: Callback?
+) : Command(injector, CommandType.CLEAR_ALARMS, callback) {
+
+ @Inject lateinit var activePlugin: ActivePlugin
+
+ override fun execute() {
+ val pump = activePlugin.activePump
+
+ if (pump is Medtrum) {
+ val medtrumPump = pump as Medtrum
+ val r = medtrumPump.clearAlarms()
+ aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
+ callback?.result(r)?.run()
+ }
+ }
+
+ override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.clear_alarms)
+
+ override fun log(): String = "CLEAR ALAMRS"
+ override fun cancel() {
+ aapsLogger.debug(LTag.PUMPQUEUE, "Result cancel")
+ callback?.result(PumpEnactResult(injector).success(false).comment(info.nightscout.core.ui.R.string.connectiontimedout))?.run()
+ }
+}
diff --git a/implementation/src/test/java/info/nightscout/implementation/queue/CommandQueueImplementationTest.kt b/implementation/src/test/java/info/nightscout/implementation/queue/CommandQueueImplementationTest.kt
index aaaa6657ce..38165f5c90 100644
--- a/implementation/src/test/java/info/nightscout/implementation/queue/CommandQueueImplementationTest.kt
+++ b/implementation/src/test/java/info/nightscout/implementation/queue/CommandQueueImplementationTest.kt
@@ -238,6 +238,11 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
// add loadEvents
commandQueue.loadEvents(null)
Assertions.assertEquals(4, commandQueue.size())
+
+ // add clearAlarms
+ commandQueue.clearAlarms(null)
+ Assertions.assertEquals(5, commandQueue.size())
+
commandQueue.clear()
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
commandQueue.pickup()
@@ -354,6 +359,22 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
Assertions.assertEquals(1, commandQueue.size())
}
+ @Test
+ fun isClearAlarmsCommandInQueue() {
+ // given
+ Assertions.assertEquals(0, commandQueue.size())
+
+ // when
+ commandQueue.clearAlarms(null)
+
+ // then
+ Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.CLEAR_ALARMS))
+ Assertions.assertEquals(1, commandQueue.size())
+ // next should be ignored
+ commandQueue.clearAlarms(null)
+ Assertions.assertEquals(1, commandQueue.size())
+ }
+
@Test
fun isLoadTDDsCommandInQueue() {
// given
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 2b66931397..de293443a1 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -383,4 +383,14 @@ import kotlin.math.round
val connectionOK = medtrumService?.setUserSettings() ?: false
return PumpEnactResult(injector).success(connectionOK)
}
+
+ override fun clearAlarms(): PumpEnactResult {
+ if (!isInitialized()) {
+ val result = PumpEnactResult(injector).success(false)
+ result.comment = "pump not initialized"
+ return result
+ }
+ val connectionOK = medtrumService?.clearAlarms() ?: false
+ return PumpEnactResult(injector).success(connectionOK)
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/EventType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/EventType.kt
index 32b4efb4ed..b1328d48cc 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/EventType.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/EventType.kt
@@ -1,8 +1,7 @@
package info.nightscout.pump.medtrum.code
enum class EventType {
- ACTIVATION_CLICKED,
- DEACTIVATION_CLICKED,
+ CHANGE_PATCH_CLICKED,
INVALID_BASAL_RATE,
PROFILE_NOT_SET,
FINISH_ACTIVITY,
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
index b38941ac91..035174e815 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/CommandType.kt
@@ -15,10 +15,12 @@ enum class CommandType(val code: Byte) {
SET_BASAL_PROFILE(21),
SET_TEMP_BASAL(24),
CANCEL_TEMP_BASAL(25),
+ RESUME_PUMP(29),
POLL_PATCH(30),
STOP_PATCH(31),
READ_BOLUS_STATE(34),
SET_PATCH(35),
SET_BOLUS_MOTOR(36),
- GET_RECORD(99)
+ GET_RECORD(99),
+ CLEAR_ALARM(115)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ClearPumpAlarmPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ClearPumpAlarmPacket.kt
new file mode 100644
index 0000000000..15f860fc50
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ClearPumpAlarmPacket.kt
@@ -0,0 +1,16 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.enums.CommandType.CLEAR_ALARM
+import info.nightscout.pump.medtrum.extension.toByteArray
+
+class ClearPumpAlarmPacket(injector: HasAndroidInjector, val clearType: Int) : MedtrumPacket(injector) {
+
+ init {
+ opCode = CLEAR_ALARM.code
+ }
+
+ override fun getRequest(): ByteArray {
+ return byteArrayOf(opCode) + clearType.toByteArray(2)
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ResumePumpPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ResumePumpPacket.kt
new file mode 100644
index 0000000000..aa613b3656
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ResumePumpPacket.kt
@@ -0,0 +1,16 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.comm.enums.CommandType.RESUME_PUMP
+import info.nightscout.pump.medtrum.extension.toByteArray
+
+class ResumePumpPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
+
+ init {
+ opCode = RESUME_PUMP.code
+ }
+
+ override fun getRequest(): ByteArray {
+ return byteArrayOf(opCode)
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
index 393a208d06..d58d9d2f33 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumCommModule.kt
@@ -6,6 +6,7 @@ import info.nightscout.pump.medtrum.comm.packets.ActivatePacket
import info.nightscout.pump.medtrum.comm.packets.AuthorizePacket
import info.nightscout.pump.medtrum.comm.packets.CancelBolusPacket
import info.nightscout.pump.medtrum.comm.packets.CancelTempBasalPacket
+import info.nightscout.pump.medtrum.comm.packets.ClearPumpAlarmPacket
import info.nightscout.pump.medtrum.comm.packets.GetDeviceTypePacket
import info.nightscout.pump.medtrum.comm.packets.GetRecordPacket
import info.nightscout.pump.medtrum.comm.packets.GetTimePacket
@@ -14,6 +15,7 @@ import info.nightscout.pump.medtrum.comm.packets.NotificationPacket
import info.nightscout.pump.medtrum.comm.packets.PollPatchPacket
import info.nightscout.pump.medtrum.comm.packets.PrimePacket
import info.nightscout.pump.medtrum.comm.packets.ReadBolusStatePacket
+import info.nightscout.pump.medtrum.comm.packets.ResumePumpPacket
import info.nightscout.pump.medtrum.comm.packets.SetBasalProfilePacket
import info.nightscout.pump.medtrum.comm.packets.SetBolusMotorPacket
import info.nightscout.pump.medtrum.comm.packets.SetBolusPacket
@@ -32,6 +34,7 @@ abstract class MedtrumCommModule {
@ContributesAndroidInjector abstract fun contributesAuthorizePacket(): AuthorizePacket
@ContributesAndroidInjector abstract fun contributesCancelBolusPacket(): CancelBolusPacket
@ContributesAndroidInjector abstract fun contributesCancelTempBasalPacket(): CancelTempBasalPacket
+ @ContributesAndroidInjector abstract fun contributesClearPumpAlarmPacket(): ClearPumpAlarmPacket
@ContributesAndroidInjector abstract fun contributesGetDeviceTypePacket(): GetDeviceTypePacket
@ContributesAndroidInjector abstract fun contributesGetRecordPacket(): GetRecordPacket
@ContributesAndroidInjector abstract fun contributesGetTimePacket(): GetTimePacket
@@ -40,6 +43,7 @@ abstract class MedtrumCommModule {
@ContributesAndroidInjector abstract fun contributesPollPatchPacket(): PollPatchPacket
@ContributesAndroidInjector abstract fun contributesPrimePacket(): PrimePacket
@ContributesAndroidInjector abstract fun contributesReadBolusStatePacket(): ReadBolusStatePacket
+ @ContributesAndroidInjector abstract fun contributesResumePumpPacket(): ResumePumpPacket
@ContributesAndroidInjector abstract fun contributesSetBasalProfilePacket(): SetBasalProfilePacket
@ContributesAndroidInjector abstract fun contributesSetBolusMotorPacket(): SetBolusMotorPacket
@ContributesAndroidInjector abstract fun contributesSetBolusPacket(): SetBolusPacket
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 1f6a836c89..00647d05cc 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -75,6 +75,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
private const val COMMAND_DEFAULT_TIMEOUT_SEC: Long = 60
private const val COMMAND_SYNC_TIMEOUT_SEC: Long = 120
private const val COMMAND_CONNECTING_TIMEOUT_SEC: Long = 30
+ private const val ALARM_HOURLY_MAX_CLEAR_CODE = 4
+ private const val ALARM_DAILY_MAX_CLEAR_CODE = 5
}
val timeUtil = MedtrumTimeUtil()
@@ -155,11 +157,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
MedtrumPumpState.LOWBG_SUSPENDED,
MedtrumPumpState.LOWBG_SUSPENDED2,
MedtrumPumpState.AUTO_SUSPENDED,
- MedtrumPumpState.HMAX_SUSPENDED,
- MedtrumPumpState.DMAX_SUSPENDED,
MedtrumPumpState.SUSPENDED,
MedtrumPumpState.PAUSED -> {
- // TODO: Message with reason
uiInteraction.addNotification(
Notification.PUMP_SUSPENDED,
rh.gs(R.string.pump_is_suspended),
@@ -168,6 +167,23 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Pump will report proper TBR for this
}
+ MedtrumPumpState.HMAX_SUSPENDED -> {
+ uiInteraction.addNotification(
+ Notification.PUMP_SUSPENDED,
+ rh.gs(R.string.pump_is_suspended_hour_max),
+ Notification.NORMAL,
+ )
+ // Pump will report proper TBR for this
+ }
+ MedtrumPumpState.DMAX_SUSPENDED -> {
+ uiInteraction.addNotification(
+ Notification.PUMP_SUSPENDED,
+ rh.gs(R.string.pump_is_suspended_day_max),
+ Notification.NORMAL,
+ )
+ // Pump will report proper TBR for this
+ }
+
MedtrumPumpState.OCCLUSION,
MedtrumPumpState.EXPIRED,
MedtrumPumpState.RESERVOIR_EMPTY,
@@ -250,18 +266,49 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun loadEvents(): Boolean {
// Send a poll patch, to workaround connection losses?
+ rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingpumpstatus)))
var result = sendPacketAndGetResponse(PollPatchPacket(injector))
// So just do a syncronize to make sure we have the latest data
if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
// Sync records (based on the info we have from the sync)
if (result) result = syncRecords()
- if (!result) {
+ if (result) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Events loaded")
+ medtrumPump.lastConnection = System.currentTimeMillis()
+ } else {
aapsLogger.error(LTag.PUMPCOMM, "Failed to sync records")
}
- if (result) medtrumPump.lastConnection = System.currentTimeMillis()
- aapsLogger.debug(LTag.PUMPCOMM, "Events loaded")
- rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingpumpstatus)))
+ return result
+ }
+
+ fun clearAlarms(): Boolean {
+ var result = true
+ when (medtrumPump.pumpState) {
+ MedtrumPumpState.HMAX_SUSPENDED -> {
+ result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, ALARM_HOURLY_MAX_CLEAR_CODE))
+ }
+ MedtrumPumpState.DMAX_SUSPENDED -> {
+ result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, ALARM_DAILY_MAX_CLEAR_CODE))
+ }
+ else -> {
+ // Do nothing
+ // TODO: Remove me before release!!!
+ // Try to brute force the commands
+ aapsLogger.warn(LTag.PUMPCOMM, "Trying to clear alarms brutus!")
+ for (i in 0..100) {
+ result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, i))
+ if (result) {
+ aapsLogger.warn(LTag.PUMPCOMM, "Alarm cleared: $i")
+ break
+ }
+ }
+ }
+ }
+ // Resume suspended pump
+ // TODO: We might not want to do this for alarms which don't suspend the pump
+ if (result) result = sendPacketAndGetResponse(ResumePumpPacket(injector))
+
return result
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index eed99396b7..98c99febd8 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -12,6 +12,7 @@ import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.EventType
import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
@@ -43,18 +44,12 @@ class MedtrumOverviewFragment : MedtrumBaseFragment
when (evt.peekContent()) {
- EventType.ACTIVATION_CLICKED -> requireContext().apply {
- // TODO: Check what to do with this, and if we need this, it currently messes up patch is last registered as priming
- // var step = convertToPatchStep(medtrumPump.pumpState)
- // if (step == PatchStep.DEACTIVATION_COMPLETE) {
- // // Reset
- // step = PatchStep.PREPARE_PATCH
- // }
- startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.PREPARE_PATCH))
- }
-
- EventType.DEACTIVATION_CLICKED -> requireContext().apply {
- startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.START_DEACTIVATION))
+ EventType.CHANGE_PATCH_CLICKED -> requireContext().apply {
+ if (medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED) {
+ startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.START_DEACTIVATION))
+ } else {
+ startActivity(MedtrumActivity.createIntentFromMenu(this, PatchStep.PREPARE_PATCH))
+ }
}
else -> Unit
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index 51eb6503d9..1e17003062 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -9,6 +9,7 @@ import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
import info.nightscout.pump.medtrum.ui.event.UIEvent
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
import info.nightscout.interfaces.profile.ProfileFunction
+import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
@@ -34,7 +35,8 @@ class MedtrumOverviewViewModel @Inject constructor(
private val aapsSchedulers: AapsSchedulers,
private val fabricPrivacy: FabricPrivacy,
private val profileFunction: ProfileFunction,
- private val medtrumPump: MedtrumPump
+ private val commandQueue: CommandQueue,
+ val medtrumPump: MedtrumPump
) : BaseViewModel() {
private val scope = CoroutineScope(Dispatchers.Default)
@@ -43,29 +45,41 @@ class MedtrumOverviewViewModel @Inject constructor(
val eventHandler: LiveData>
get() = _eventHandler
+ private val _canDoRefresh = SingleLiveEvent()
+ val canDoRefresh: LiveData
+ get() = _canDoRefresh
+
+ private val _canDoResetAlarms = SingleLiveEvent()
+ val canDoResetAlarms: LiveData
+ get() = _canDoResetAlarms
+
private val _bleStatus = SingleLiveEvent()
val bleStatus: LiveData
get() = _bleStatus
- private val _isPatchActivated = SingleLiveEvent()
- val isPatchActivated: LiveData
- get() = _isPatchActivated
+ private val _lastConnected = SingleLiveEvent()
+ val lastConnected: LiveData
+ get() = _lastConnected
- private val _pumpState = SingleLiveEvent()
- val pumpState: LiveData
- get() = _pumpState
+ private val _activeAlarms = SingleLiveEvent()
+ val activeAlarms: LiveData
+ get() = _activeAlarms
- private val _basalType = SingleLiveEvent()
- val basalType: LiveData
- get() = _basalType
+ private val _pumpType = SingleLiveEvent()
+ val pumpType: LiveData
+ get() = _pumpType
- private val _runningBasalRate = SingleLiveEvent()
- val runningBasalRate: LiveData
- get() = _runningBasalRate
+ private val _fwVersion = SingleLiveEvent()
+ val fwVersion: LiveData
+ get() = _fwVersion
+
+ private val _patchNo = SingleLiveEvent()
+ val patchNo: LiveData
+ get() = _patchNo
- private val _reservoir = SingleLiveEvent()
- val reservoir: LiveData
- get() = _reservoir
+ private val _patchExpiry = SingleLiveEvent()
+ val patchExpiry: LiveData
+ get() = _patchExpiry
init {
scope.launch {
@@ -74,14 +88,21 @@ class MedtrumOverviewViewModel @Inject constructor(
when (state) {
ConnectionState.CONNECTING -> {
_bleStatus.postValue("{fa-bluetooth-b spin}")
+ _canDoRefresh.postValue(false)
}
ConnectionState.CONNECTED -> {
_bleStatus.postValue("{fa-bluetooth}")
+ _canDoRefresh.postValue(false)
}
ConnectionState.DISCONNECTED -> {
_bleStatus.postValue("{fa-bluetooth-b}")
+ if (medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED) {
+ _canDoRefresh.postValue(true)
+ } else {
+ _canDoRefresh.postValue(false)
+ }
}
}
}
@@ -89,37 +110,13 @@ class MedtrumOverviewViewModel @Inject constructor(
scope.launch {
medtrumPump.pumpStateFlow.collect { state ->
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
- if (state > MedtrumPumpState.EJECTED && state < MedtrumPumpState.STOPPED) {
- _isPatchActivated.postValue(true)
+ if (medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED) {
+ _canDoResetAlarms.postValue(true)
} else {
- _isPatchActivated.postValue(false)
+ _canDoResetAlarms.postValue(false)
}
}
}
- scope.launch {
- medtrumPump.lastBasalRateFlow.collect { rate ->
- aapsLogger.debug(LTag.PUMP, "MedtrumViewModel runningBasalRateFlow: $rate")
- _runningBasalRate.postValue(String.format(rh.gs(R.string.current_basal_rate), rate))
- }
- }
- scope.launch {
- medtrumPump.pumpStateFlow.collect { state ->
- aapsLogger.debug(LTag.PUMP, "MedtrumViewModel pumpStateFlow: $state")
- _pumpState.postValue(state.toString())
- }
- }
- scope.launch {
- medtrumPump.reservoirFlow.collect { reservoir ->
- aapsLogger.debug(LTag.PUMP, "MedtrumViewModel reservoirFlow: $reservoir")
- _reservoir.postValue(String.format(rh.gs(R.string.reservoir_level), reservoir))
- }
- }
- scope.launch {
- medtrumPump.lastBasalTypeFlow.collect { basalType ->
- aapsLogger.debug(LTag.PUMP, "MedtrumViewModel basalTypeFlow: $basalType")
- _basalType.postValue(basalType.toString())
- }
- }
}
override fun onCleared() {
@@ -127,18 +124,22 @@ class MedtrumOverviewViewModel @Inject constructor(
scope.cancel()
}
- fun onClickActivation() {
- aapsLogger.debug(LTag.PUMP, "Start Patch clicked!")
+ fun onClickRefresh() {
+ commandQueue.readStatus(rh.gs(R.string.requested_by_user), null)
+ }
+
+ fun onClickResetAlarms() {
+ commandQueue.clearAlarms(null)
+ }
+
+ fun onClickChangePatch() {
+ aapsLogger.debug(LTag.PUMP, "ChangePatch Patch clicked!")
val profile = profileFunction.getProfile()
if (profile == null) {
_eventHandler.postValue(UIEvent(EventType.PROFILE_NOT_SET))
} else {
- _eventHandler.postValue(UIEvent(EventType.ACTIVATION_CLICKED))
+ _eventHandler.postValue(UIEvent(EventType.CHANGE_PATCH_CLICKED))
}
}
-
- fun onClickDeactivation() {
- aapsLogger.debug(LTag.PUMP, "Stop Patch clicked!")
- _eventHandler.postValue(UIEvent(EventType.DEACTIVATION_CLICKED))
- }
-}
\ No newline at end of file
+}
+
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index 398c351044..866e869bb0 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -27,235 +27,474 @@
+ android:paddingBottom="5dp">
-
+
-
+ android:orientation="horizontal">
-
+
-
+
-
+
+
+
+
+ android:orientation="horizontal">
-
+
-
+
+
+
+
+
+
+
+
+ android:layout_marginVertical="3dp"
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -267,26 +506,38 @@
android:layout_alignParentBottom="true"
android:orientation="horizontal">
+
+ android:enabled="@{viewmodel.canDoRefresh}"
+ android:text="@string/refresh_label"
+ app:onSafeClick="@{() -> viewmodel.onClickRefresh()}" />
+
+ android:text="@string/reset_alarms_label"
+ android:enabled="@{viewmodel.canDoResetAlarms}"
+ app:onSafeClick="@{() -> viewmodel.onClickResetAlarms()}" />
+
+
+
-
\ No newline at end of file
+
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 958da20f9d..c6fde4588a 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -21,19 +21,29 @@
Medtrum pump settings
Pump error: %1$s !!
Pump is suspended
+ Pump is suspended due to hourly max insulin exceeded
+ Pump is suspended due to daily max insulin exceeded
Patch not activated
Setting user settings to pump failed!
- BLE Status
+ BLE Status
+ Last connected
Pump state
+ Active alarms
Reservoir
%.2f U
- Basal type
- Basal rate
+ Basal type
+ Basal rate
%.2f U/h
- Start new patch
- Stop patch
+ Pump type
+ FW version
+ Patch no
+ Patch expires
+ Refresh
+ Reset alarms
+ Change patch
+ Requested by user
Discard/Change Patch
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ClearPumpAlarmPacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ClearPumpAlarmPacketTest.kt
new file mode 100644
index 0000000000..b1afad48d2
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ClearPumpAlarmPacketTest.kt
@@ -0,0 +1,36 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import info.nightscout.pump.medtrum.extension.toInt
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class ClearPumpAlarmPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 115
+ val clearCode = 4
+
+ // Call
+ val packet = ClearPumpAlarmPacket(packetInjector, clearCode)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(3, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ assertEquals(clearCode, result.copyOfRange(1, 3).toInt())
+ }
+}
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ResumePumpPacket.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ResumePumpPacket.kt
new file mode 100644
index 0000000000..05ddc499a5
--- /dev/null
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/ResumePumpPacket.kt
@@ -0,0 +1,33 @@
+package info.nightscout.pump.medtrum.comm.packets
+
+import dagger.android.AndroidInjector
+import dagger.android.HasAndroidInjector
+import info.nightscout.pump.medtrum.MedtrumTestBase
+import org.junit.jupiter.api.Test
+import org.junit.Assert.*
+
+class ResumePumpPacketTest : MedtrumTestBase() {
+
+ /** Test packet specific behavoir */
+
+ private val packetInjector = HasAndroidInjector {
+ AndroidInjector {
+ if (it is MedtrumPacket) {
+ it.aapsLogger = aapsLogger
+ }
+ }
+ }
+
+ @Test fun getRequestGivenPacketWhenCalledThenReturnOpCode() {
+ // Inputs
+ val opCode = 29
+
+ // Call
+ val packet = ResumePumpPacket(packetInjector)
+ val result = packet.getRequest()
+
+ // Expected values
+ assertEquals(1, result.size)
+ assertEquals(opCode.toByte(), result[0])
+ }
+}
From c0138ffad8be8353cd9f4bc3efa9ddef9933076f Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Fri, 16 Jun 2023 21:01:59 +0200
Subject: [PATCH 042/116] Add lastConnection and expiry to overview
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 12 ++++-
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 49 +++++++++++++------
.../res/layout/fragment_medtrum_overview.xml | 34 +++++++------
pump/medtrum/src/main/res/values/strings.xml | 6 ++-
4 files changed, 68 insertions(+), 33 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index d6f46b2fea..3fa0b709c5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -132,16 +132,23 @@ class MedtrumPump @Inject constructor(
sp.putString(R.string.key_actual_basal_profile, encodedString ?: "")
}
+ private var _lastConnection = 0L // Time in ms!
+ var lastConnection: Long
+ get() = _lastConnection
+ set(value) {
+ _lastConnection = value
+ sp.putLong(R.string.key_last_connection, value)
+ }
+
private var _pumpSN = 0L
val pumpSN: Long
get() = _pumpSN
val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection
- var lastConnection = 0L // Time in ms!
var lastTimeReceivedFromPump = 0L // Time in ms! // TODO: Consider removing as is not used?
var suspendTime = 0L // Time in ms!
- var patchStartTime = 0L // Time in ms!
+ var patchStartTime = 0L // Time in ms! // TODO: save in SP
var patchAge = 0L // Time in seconds?! // TODO: Not used
var batteryVoltage_A = 0.0
@@ -186,6 +193,7 @@ class MedtrumPump @Inject constructor(
init {
// Load stuff from SP
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
+ _lastConnection = sp.getLong(R.string.key_last_connection, 0L)
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
_patchId = sp.getLong(R.string.key_patch_id, 0L)
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index 1e17003062..f2dfa87af9 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -1,27 +1,21 @@
package info.nightscout.pump.medtrum.ui.viewmodel
import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.pump.medtrum.code.EventType
import info.nightscout.pump.medtrum.ui.MedtrumBaseNavigator
import info.nightscout.pump.medtrum.ui.event.SingleLiveEvent
import info.nightscout.pump.medtrum.ui.event.UIEvent
-import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
-import info.nightscout.rx.AapsSchedulers
-import info.nightscout.rx.bus.RxBus
-import info.nightscout.rx.events.EventPumpStatusChanged
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
-import io.reactivex.rxjava3.disposables.CompositeDisposable
-import io.reactivex.rxjava3.kotlin.plusAssign
+import info.nightscout.shared.utils.DateUtil
+import info.nightscout.shared.utils.T
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
@@ -31,11 +25,9 @@ import javax.inject.Inject
class MedtrumOverviewViewModel @Inject constructor(
private val aapsLogger: AAPSLogger,
private val rh: ResourceHelper,
- private val rxBus: RxBus,
- private val aapsSchedulers: AapsSchedulers,
- private val fabricPrivacy: FabricPrivacy,
private val profileFunction: ProfileFunction,
private val commandQueue: CommandQueue,
+ private val dateUtil: DateUtil,
val medtrumPump: MedtrumPump
) : BaseViewModel() {
@@ -57,9 +49,9 @@ class MedtrumOverviewViewModel @Inject constructor(
val bleStatus: LiveData
get() = _bleStatus
- private val _lastConnected = SingleLiveEvent()
- val lastConnected: LiveData
- get() = _lastConnected
+ private val _lastConnectionMinAgo = SingleLiveEvent()
+ val lastConnectionMinAgo: LiveData
+ get() = _lastConnectionMinAgo
private val _activeAlarms = SingleLiveEvent()
val activeAlarms: LiveData
@@ -105,6 +97,7 @@ class MedtrumOverviewViewModel @Inject constructor(
}
}
}
+ updateGUI()
}
}
scope.launch {
@@ -115,6 +108,14 @@ class MedtrumOverviewViewModel @Inject constructor(
} else {
_canDoResetAlarms.postValue(false)
}
+ updateGUI()
+ }
+ }
+ // Periodically update gui
+ scope.launch {
+ while (true) {
+ updateGUI()
+ kotlinx.coroutines.delay(T.mins(1).msecs())
}
}
}
@@ -141,5 +142,25 @@ class MedtrumOverviewViewModel @Inject constructor(
_eventHandler.postValue(UIEvent(EventType.CHANGE_PATCH_CLICKED))
}
}
+
+ fun updateGUI() {
+ // Update less dynamic values
+ val agoMilliseconds = System.currentTimeMillis() - medtrumPump.lastConnection
+ val agoMinutes = agoMilliseconds / 1000 / 60
+ _lastConnectionMinAgo.postValue(rh.gs(info.nightscout.shared.R.string.minago, agoMinutes))
+
+ // TODO: Update these values
+ // _activeAlarms.postValue(rh.gs(R.string.active_alarms, pump.activeAlarms))
+ // _pumpType.postValue(rh.gs(R.string.pump_type, pump.pumpType))
+ // _fwVersion.postValue(rh.gs(R.string.fw_version, pump.fwVersion))
+ // _patchNo.postValue(rh.gs(R.string.patch_no, pump.patchNo))
+
+ if (medtrumPump.desiredPatchExpiration) {
+ val expiry = medtrumPump.patchStartTime + T.hours(84).msecs()
+ _patchExpiry.postValue(dateUtil.dateAndTimeString(expiry))
+ } else {
+ _patchExpiry.postValue(rh.gs(R.string.expiry_not_enabled))
+ }
+ }
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index 866e869bb0..c9f6cd5be7 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -3,7 +3,6 @@
xmlns:tools="http://schemas.android.com/tools">
-
@@ -82,7 +81,7 @@
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
- android:text="@string/last_connected_label"
+ android:text="@string/last_connection_label"
android:textSize="14sp" />
@@ -111,9 +110,11 @@
+ android:background="?android:attr/dividerHorizontal" />
+ android:background="?android:attr/dividerHorizontal" />
+
+
-
-
-
-
+
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index c6fde4588a..63f97eee88 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -9,6 +9,7 @@
medtrumpump_settings
pump_state
+ last_connection
medtrum_session_token
patch_id
actual_basal_profile
@@ -28,7 +29,7 @@
BLE Status
- Last connected
+ Last connected
Pump state
Active alarms
Reservoir
@@ -44,6 +45,7 @@
Reset alarms
Change patch
Requested by user
+ Not enabled
Discard/Change Patch
@@ -66,7 +68,7 @@
Alarm Settings
Select your preferred pump alarm settings.
Patch Expiration
- Turn this on to get an alert 12 hours before the patch expiration. When enabled, the patch will expire after 3 days.
+ Turn this on to get an alert 12 hours before the patch expiration. When enabled, the patch will expire after 3.5 days.
Hourly Maximum Insulin
Specify the maximum units of insulin allowed per hour. If exceeded, the pump will suspend.
Daily Maximum Insulin
From 082b36552064af52c7713c4a4e17916ff8bf8c93 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 17 Jun 2023 08:44:04 +0200
Subject: [PATCH 043/116] Added more info to overview
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 42 +++++++++++++++++--
.../medtrum/comm/packets/AuthorizePacket.kt | 16 ++++---
.../comm/packets/NotificationPacket.kt | 8 +++-
.../pump/medtrum/services/MedtrumService.kt | 6 +--
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 6 +--
.../res/layout/fragment_medtrum_overview.xml | 40 ++++++++++++++++++
pump/medtrum/src/main/res/values/strings.xml | 5 +++
.../comm/packets/AuthorizePacketTest.kt | 4 +-
8 files changed, 106 insertions(+), 21 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 3fa0b709c5..35b7ccb442 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -90,6 +90,15 @@ class MedtrumPump @Inject constructor(
_reservoir.value = value
}
+ var batteryVoltage_A = 0.0 // Not used in UI
+ private val _batteryVoltage_B = MutableStateFlow(0.0)
+ val batteryVoltage_BFlow: StateFlow = _batteryVoltage_B
+ var batteryVoltage_B: Double
+ get() = _batteryVoltage_B.value
+ set(value) {
+ _batteryVoltage_B.value = value
+ }
+
/** Stuff stored in SP */
private var _patchSessionToken = 0L
var patchSessionToken: Long
@@ -140,19 +149,41 @@ class MedtrumPump @Inject constructor(
sp.putLong(R.string.key_last_connection, value)
}
+ private var _deviceType: Int = 0 // As reported by pump
+ var deviceType: Int
+ get() = _deviceType
+ set(value) {
+ _deviceType = value
+ sp.putInt(R.string.key_device_type, value)
+ }
+
+ private var _swVersion: String = "" // As reported by pump
+ var swVersion: String
+ get() = _swVersion
+ set(value) {
+ _swVersion = value
+ sp.putString(R.string.key_sw_version, value)
+ }
+
+ private var _patchStartTime = 0L // Time in ms!
+ var patchStartTime: Long
+ get() = _patchStartTime
+ set(value) {
+ _patchStartTime = value
+ sp.putLong(R.string.key_patch_start_time, value)
+ }
+
private var _pumpSN = 0L
val pumpSN: Long
get() = _pumpSN
- val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on pumpSN or pump activation/connection
+ val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on deviceType from pump
var lastTimeReceivedFromPump = 0L // Time in ms! // TODO: Consider removing as is not used?
var suspendTime = 0L // Time in ms!
- var patchStartTime = 0L // Time in ms! // TODO: save in SP
+
var patchAge = 0L // Time in seconds?! // TODO: Not used
- var batteryVoltage_A = 0.0
- var batteryVoltage_B = 0.0
var alarmFlags = 0
var alarmParameter = 0
@@ -198,6 +229,9 @@ class MedtrumPump @Inject constructor(
_patchId = sp.getLong(R.string.key_patch_id, 0L)
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
_pumpState.value = MedtrumPumpState.fromByte(sp.getInt(R.string.key_pump_state, MedtrumPumpState.NONE.state.toInt()).toByte())
+ _deviceType = sp.getInt(R.string.key_device_type, 0)
+ _swVersion = sp.getString(R.string.key_sw_version, "")
+ _patchStartTime = sp.getLong(R.string.key_patch_start_time, 0L)
val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
try {
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
index 4cf10a580c..fce1d8c869 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacket.kt
@@ -6,15 +6,13 @@ import info.nightscout.pump.medtrum.comm.enums.CommandType.AUTH_REQ
import info.nightscout.pump.medtrum.encryption.Crypt
import info.nightscout.pump.medtrum.extension.toByteArray
import info.nightscout.pump.medtrum.extension.toInt
+import info.nightscout.rx.logging.LTag
import javax.inject.Inject
class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
@Inject lateinit var medtrumPump: MedtrumPump
- var deviceType: Int = 0
- var swVersion: String = ""
-
companion object {
private const val RESP_DEVICE_TYPE_START = 7
@@ -41,10 +39,18 @@ class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
override fun handleResponse(data: ByteArray): Boolean {
val success = super.handleResponse(data)
if (success) {
- deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
- swVersion = "" + data.copyOfRange(RESP_VERSION_X_START, RESP_VERSION_X_END).toInt() + "." + data.copyOfRange(RESP_VERSION_Y_START, RESP_VERSION_Y_END).toInt() + "." + data.copyOfRange(
+ val deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
+ val swVersion = "" + data.copyOfRange(RESP_VERSION_X_START, RESP_VERSION_X_END).toInt() + "." + data.copyOfRange(RESP_VERSION_Y_START, RESP_VERSION_Y_END).toInt() + "." + data.copyOfRange(
RESP_VERSION_Z_START, RESP_VERSION_Z_END
).toInt()
+
+ if (medtrumPump.deviceType != deviceType) {
+ medtrumPump.deviceType = deviceType
+ }
+ if (medtrumPump.swVersion != swVersion) {
+ medtrumPump.swVersion = swVersion
+ }
+ aapsLogger.debug(LTag.PUMPCOMM, "GetDeviceTypeState: deviceType: ${deviceType}, swVersion: ${swVersion}")
}
return success
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index c8f1a215fa..1072086ca9 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -188,8 +188,12 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (fieldMask and MASK_START_TIME != 0) {
aapsLogger.debug(LTag.PUMPCOMM, "Start time notification received")
- medtrumPump.patchStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset, offset + 4).toLong())
- aapsLogger.debug(LTag.PUMPCOMM, "Patch start time: ${medtrumPump.patchStartTime}")
+ val patchStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset, offset + 4).toLong())
+ if (medtrumPump.patchStartTime != patchStartTime) {
+ aapsLogger.debug(LTag.PUMPCOMM, "Patch start time changed from ${medtrumPump.patchStartTime} to $patchStartTime")
+ medtrumPump.patchStartTime = patchStartTime
+ }
+ aapsLogger.debug(LTag.PUMPCOMM, "Patch start time: ${patchStartTime}")
offset += 4
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 00647d05cc..39f84d208f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -586,11 +586,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
if (mPacket?.handleResponse(data) == true) {
// Succes!
responseHandled = true
- responseSuccess = true
- // TODO Get pump version info
- val deviceType = (mPacket as AuthorizePacket).deviceType
- val swVersion = (mPacket as AuthorizePacket).swVersion
- aapsLogger.debug(LTag.PUMPCOMM, "GetDeviceTypeState: deviceType: $deviceType swVersion: $swVersion") // TODO remove me later
+ responseSuccess = true
toState(GetDeviceTypeState())
} else if (mPacket?.failed == true) {
// Failure
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index f2dfa87af9..d33de4aa71 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -151,9 +151,9 @@ class MedtrumOverviewViewModel @Inject constructor(
// TODO: Update these values
// _activeAlarms.postValue(rh.gs(R.string.active_alarms, pump.activeAlarms))
- // _pumpType.postValue(rh.gs(R.string.pump_type, pump.pumpType))
- // _fwVersion.postValue(rh.gs(R.string.fw_version, pump.fwVersion))
- // _patchNo.postValue(rh.gs(R.string.patch_no, pump.patchNo))
+ _pumpType.postValue(medtrumPump.deviceType.toString())
+ _fwVersion.postValue(medtrumPump.swVersion)
+ _patchNo.postValue(medtrumPump.patchId.toString())
if (medtrumPump.desiredPatchExpiration) {
val expiry = medtrumPump.patchStartTime + T.hours(84).msecs()
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index c9f6cd5be7..1c3fb68e39 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -276,6 +276,46 @@
android:textSize="14sp" />
+
+
+
+
+
+
+
+
+
+
last_connection
medtrum_session_token
patch_id
+ device_type
+ sw_version
+ patch_start_time
actual_basal_profile
current_sequence_number
synced_sequence_number
@@ -34,6 +37,8 @@
Active alarms
Reservoir
%.2f U
+ Battery
+ %.2f V
Basal type
Basal rate
%.2f U/h
diff --git a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
index 7c07339220..697d439e25 100644
--- a/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
+++ b/pump/medtrum/src/test/java/info/nightscout/pump/medtrum/comm/packets/AuthorizePacketTest.kt
@@ -59,8 +59,8 @@ class AuthorizePacketTest : MedtrumTestBase() {
val swString = "$swVerX.$swVerY.$swVerZ"
assertTrue(result)
assertFalse(packet.failed)
- assertEquals(deviceType, packet.deviceType)
- assertEquals(swString, packet.swVersion)
+ assertEquals(deviceType, medtrumPump.deviceType)
+ assertEquals(swString, medtrumPump.swVersion)
}
@Test fun handleResponseGivenResponseWhenMessageTooShortThenResultFalse() {
From 996ef8e5ef98df6a7c489ed0a9f0436cbbc6deec Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sat, 17 Jun 2023 15:29:35 +0200
Subject: [PATCH 044/116] Implement getJSONStatus() and shortStatus()
---
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 59 ++++++-
.../nightscout/pump/medtrum/MedtrumPump.kt | 62 +++++---
.../medtrum/comm/packets/GetRecordPacket.kt | 5 +
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 21 ++-
.../res/layout/fragment_medtrum_overview.xml | 150 +++++++++++++-----
pump/medtrum/src/main/res/values/strings.xml | 4 +-
.../src/main/res/xml/pref_medtrum_pump.xml | 2 +-
7 files changed, 234 insertions(+), 69 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index de293443a1..ca1cecc7b3 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -5,6 +5,7 @@ import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
+import android.text.format.DateFormat
import dagger.android.HasAndroidInjector
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.fabric.FabricPrivacy
@@ -31,6 +32,7 @@ import info.nightscout.interfaces.pump.defs.PumpType
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.queue.CustomCommand
import info.nightscout.interfaces.ui.UiInteraction
+import info.nightscout.interfaces.utils.DecimalFormatter
import info.nightscout.interfaces.utils.TimeChangeType
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
@@ -222,7 +224,7 @@ import kotlin.math.round
get() = medtrumPump.reservoir
override val batteryLevel: Int
- get() = 0 // TODO
+ get() = 0 // We cannot determine battery level (yet)
@Synchronized
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
@@ -317,7 +319,43 @@ import kotlin.math.round
}
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
- return JSONObject() // TODO
+ val now = System.currentTimeMillis()
+ if (medtrumPump.lastConnection + 60 * 60 * 1000L < System.currentTimeMillis()) {
+ return JSONObject()
+ }
+ val pumpJson = JSONObject()
+ val status = JSONObject()
+ val extended = JSONObject()
+ try {
+ status.put(
+ "status", if (!isSuspended()) "normal"
+ else if (isInitialized() && isSuspended()) "suspended"
+ else "no active patch"
+ )
+ status.put("timestamp", dateUtil.toISOString(medtrumPump.lastConnection))
+ if (medtrumPump.lastBolusTime != 0L) {
+ extended.put("lastBolus", dateUtil.dateAndTimeString(medtrumPump.lastBolusTime))
+ extended.put("lastBolusAmount", medtrumPump.lastBolusAmount)
+ }
+ val tb = pumpSync.expectedPumpState().temporaryBasal
+ if (tb != null) {
+ extended.put("TempBasalAbsoluteRate", tb.convertedToAbsolute(now, profile))
+ extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.timestamp))
+ extended.put("TempBasalRemaining", tb.plannedRemainingMinutes)
+ }
+ extended.put("BaseBasalRate", baseBasalRate)
+ try {
+ extended.put("ActiveProfile", profileName)
+ } catch (ignored: Exception) {
+ }
+ pumpJson.put("status", status)
+ pumpJson.put("extended", extended)
+ pumpJson.put("reservoir", medtrumPump.reservoir.toInt())
+ pumpJson.put("clock", dateUtil.toISOString(now))
+ } catch (e: JSONException) {
+ aapsLogger.error(LTag.PUMP, "Unhandled exception: $e")
+ }
+ return pumpJson
}
override fun manufacturer(): ManufacturerType {
@@ -336,7 +374,20 @@ import kotlin.math.round
get() = PumpDescription(medtrumPump.pumpType)
override fun shortStatus(veryShort: Boolean): String {
- return ""// TODO
+ var ret = ""
+ if (medtrumPump.lastConnection != 0L) {
+ val agoMillis = System.currentTimeMillis() - medtrumPump.lastConnection
+ val agoMin = (agoMillis / 60.0 / 1000.0).toInt()
+ ret += "LastConn: $agoMin minAgo\n"
+ }
+ if (medtrumPump.lastBolusTime != 0L)
+ ret += "LastBolus: ${DecimalFormatter.to2Decimal(medtrumPump.lastBolusAmount)}U @${DateFormat.format("HH:mm", medtrumPump.lastBolusTime)}\n"
+
+ if (medtrumPump.tempBasalInProgress)
+ ret += "Temp: ${medtrumPump.temporaryBasalToString()}\n"
+
+ ret += "Res: ${DecimalFormatter.to0Decimal(medtrumPump.reservoir)}U\n"
+ return ret
}
override val isFakingTempsByExtendedBoluses: Boolean = false
@@ -375,7 +426,7 @@ import kotlin.math.round
}
override fun setUserOptions(): PumpEnactResult {
- if (!isInitialized()) {
+ if (!isInitialized()) {
val result = PumpEnactResult(injector).success(false)
result.comment = "pump not initialized"
return result
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 35b7ccb442..5110ee1e27 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -68,19 +68,13 @@ class MedtrumPump @Inject constructor(
private var _lastBasalType: MutableStateFlow = MutableStateFlow(BasalType.NONE)
val lastBasalTypeFlow: StateFlow = _lastBasalType
- var lastBasalType: BasalType
+ val lastBasalType: BasalType
get() = _lastBasalType.value
- set(value) {
- _lastBasalType.value = value
- }
private val _lastBasalRate = MutableStateFlow(0.0)
val lastBasalRateFlow: StateFlow = _lastBasalRate
- var lastBasalRate: Double
+ val lastBasalRate: Double
get() = _lastBasalRate.value
- set(value) {
- _lastBasalRate.value = value
- }
private val _reservoir = MutableStateFlow(0.0)
val reservoirFlow: StateFlow = _reservoir
@@ -141,6 +135,22 @@ class MedtrumPump @Inject constructor(
sp.putString(R.string.key_actual_basal_profile, encodedString ?: "")
}
+ private var _lastBolusTime = 0L // Time in ms!
+ var lastBolusTime: Long
+ get() = _lastBolusTime
+ set(value) {
+ _lastBolusTime = value
+ sp.putLong(R.string.key_last_bolus_time, value)
+ }
+
+ private var _lastBolusAmount = 0.0
+ var lastBolusAmount: Double
+ get() = _lastBolusAmount
+ set(value) {
+ _lastBolusAmount = value
+ sp.putDouble(R.string.key_last_bolus_amount, value)
+ }
+
private var _lastConnection = 0L // Time in ms!
var lastConnection: Long
get() = _lastConnection
@@ -181,7 +191,6 @@ class MedtrumPump @Inject constructor(
var lastTimeReceivedFromPump = 0L // Time in ms! // TODO: Consider removing as is not used?
var suspendTime = 0L // Time in ms!
-
var patchAge = 0L // Time in seconds?! // TODO: Not used
@@ -196,11 +205,18 @@ class MedtrumPump @Inject constructor(
var bolusStopForced = false // bolus forced to stop by user
var bolusDone = false // success end
- // Last basal status update
- // TODO maybe make basal parameters private? So we are forced to update trough handleBasalStatusUpdate
- var lastBasalSequence = 0
- var lastBasalPatchId = 0L
- var lastBasalStartTime = 0L
+ // Last basal status update (from pump)
+ private var _lastBasalSequence = 0
+ val lastBasalSequence: Int
+ get() = _lastBasalSequence
+
+ private var _lastBasalPatchId = 0L
+ val lastBasalPatchId: Long
+ get() = _lastBasalPatchId
+
+ private var _lastBasalStartTime = 0L
+ val lastBasalStartTime: Long
+ get() = _lastBasalStartTime
val baseBasalRate: Double
get() = getHourlyBasalFromMedtrumProfileArray(actualBasalProfile, dateUtil.now())
@@ -225,6 +241,8 @@ class MedtrumPump @Inject constructor(
// Load stuff from SP
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
_lastConnection = sp.getLong(R.string.key_last_connection, 0L)
+ _lastBolusTime = sp.getLong(R.string.key_last_bolus_time, 0L)
+ _lastBolusAmount = sp.getDouble(R.string.key_last_bolus_amount, 0.0)
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
_patchId = sp.getLong(R.string.key_patch_id, 0L)
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
@@ -243,7 +261,7 @@ class MedtrumPump @Inject constructor(
fun loadUserSettingsFromSP() {
desiredPatchExpiration = sp.getBoolean(info.nightscout.pump.medtrum.R.string.key_patch_expiration, false)
- val alarmSettingCode = sp.getString(info.nightscout.pump.medtrum.R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code.toString())?.toByte()
+ val alarmSettingCode = sp.getString(info.nightscout.pump.medtrum.R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code.toString()).toByte()
desiredAlarmSetting = AlarmSetting.values().firstOrNull { it.code == alarmSettingCode } ?: AlarmSetting.LIGHT_VIBRATE_AND_BEEP
desiredHourlyMaxInsulin = sp.getInt(info.nightscout.pump.medtrum.R.string.key_hourly_max_insulin, 40)
desiredDailyMaxInsulin = sp.getInt(info.nightscout.pump.medtrum.R.string.key_daily_max_insulin, 180)
@@ -370,17 +388,17 @@ class MedtrumPump @Inject constructor(
}
// Update medtrum pump state
- lastBasalType = basalType
- lastBasalRate = basalRate
- lastBasalSequence = basalSequence
+ _lastBasalType.value = basalType
+ _lastBasalRate.value = basalRate
+ _lastBasalSequence = basalSequence
if (basalSequence > currentSequenceNumber) {
currentSequenceNumber = basalSequence
}
- lastBasalPatchId = basalPatchId
+ _lastBasalPatchId = basalPatchId
if (basalPatchId != patchId) {
aapsLogger.error(LTag.PUMP, "handleBasalStatusUpdate: WTF? PatchId in status update does not match current patchId!")
}
- lastBasalStartTime = basalStartTime
+ _lastBasalStartTime = basalStartTime
}
fun handleStopStatusUpdate(stopSequence: Int, stopPatchId: Long) {
@@ -418,4 +436,8 @@ class MedtrumPump @Inject constructor(
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START (FAKE)"
)
}
+ fun temporaryBasalToString(): String {
+ if (!tempBasalInProgress) return ""
+ return tempBasalAbsoluteRate.toString() + "U/h"
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
index 600f2223cf..265e7b3ae9 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -125,7 +125,12 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
// detailedInfo can be from another similar record. Reinsert
detailedBolusInfoStorage.add(detailedBolusInfo)
}
+ if (bolusStartTime > medtrumPump.lastBolusTime) {
+ medtrumPump.lastBolusTime = bolusStartTime
+ medtrumPump.lastBolusAmount = bolusNormalDelivered
+ }
} else {
+ // TODO: at least record the bolus
aapsLogger.error(
LTag.PUMPCOMM,
"from record: EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) " + "Bolus type: $bolusType not supported"
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index d33de4aa71..85a2db7fba 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -53,6 +53,10 @@ class MedtrumOverviewViewModel @Inject constructor(
val lastConnectionMinAgo: LiveData
get() = _lastConnectionMinAgo
+ private val _lastBolus = SingleLiveEvent()
+ val lastBolus: LiveData
+ get() = _lastBolus
+
private val _activeAlarms = SingleLiveEvent()
val activeAlarms: LiveData
get() = _activeAlarms
@@ -64,7 +68,7 @@ class MedtrumOverviewViewModel @Inject constructor(
private val _fwVersion = SingleLiveEvent()
val fwVersion: LiveData
get() = _fwVersion
-
+
private val _patchNo = SingleLiveEvent()
val patchNo: LiveData
get() = _patchNo
@@ -148,6 +152,21 @@ class MedtrumOverviewViewModel @Inject constructor(
val agoMilliseconds = System.currentTimeMillis() - medtrumPump.lastConnection
val agoMinutes = agoMilliseconds / 1000 / 60
_lastConnectionMinAgo.postValue(rh.gs(info.nightscout.shared.R.string.minago, agoMinutes))
+ if (medtrumPump.lastBolusTime != 0L) {
+ val agoMilliseconds = System.currentTimeMillis() - medtrumPump.lastBolusTime
+ val agoHours = agoMilliseconds.toDouble() / 60.0 / 60.0 / 1000.0
+ if (agoHours < 6)
+ // max 6h back
+ _lastBolus.postValue(
+ dateUtil.timeString(medtrumPump.lastBolusTime) + " " + dateUtil.sinceString(medtrumPump.lastBolusTime, rh) + " " + rh.gs(
+ info.nightscout.interfaces.R.string
+ .format_insulin_units, medtrumPump
+ .lastBolusAmount
+ )
+ )
+ else
+ _lastBolus.postValue("")
+ }
// TODO: Update these values
// _activeAlarms.postValue(rh.gs(R.string.active_alarms, pump.activeAlarms))
diff --git a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
index 1c3fb68e39..9634d4fc49 100644
--- a/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
+++ b/pump/medtrum/src/main/res/layout/fragment_medtrum_overview.xml
@@ -34,6 +34,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
medtrumpump_settings
pump_state
last_connection
+ last_bolus_time
+ last_bolus_amount
medtrum_session_token
patch_id
device_type
@@ -35,9 +37,7 @@
Last connected
Pump state
Active alarms
- Reservoir
%.2f U
- Battery
%.2f V
Basal type
Basal rate
diff --git a/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml b/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
index c87d2384d2..9195ccdf9f 100644
--- a/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
+++ b/pump/medtrum/src/main/res/xml/pref_medtrum_pump.xml
@@ -9,7 +9,7 @@
From 057b2e386e5671a7f5deec71867eee68134b22a3 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 18 Jun 2023 20:36:44 +0200
Subject: [PATCH 045/116] Add alarm states, show active alarms in overview
---
.../nightscout/pump/medtrum/MedtrumPump.kt | 45 +++-
.../pump/medtrum/comm/enums/AlarmState.kt | 23 ++
.../comm/packets/NotificationPacket.kt | 30 ++-
.../pump/medtrum/services/MedtrumService.kt | 229 ++++++++++--------
.../medtrum/ui/MedtrumOverviewFragment.kt | 1 +
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 30 ++-
pump/medtrum/src/main/res/values/strings.xml | 22 ++
7 files changed, 275 insertions(+), 105 deletions(-)
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/AlarmState.kt
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 5110ee1e27..381ec89b88 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -7,6 +7,7 @@ import info.nightscout.interfaces.pump.TemporaryBasalStorage
import info.nightscout.interfaces.pump.defs.PumpType
import info.nightscout.pump.medtrum.code.ConnectionState
import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
+import info.nightscout.pump.medtrum.comm.enums.AlarmState
import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toByteArray
@@ -19,7 +20,7 @@ import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
-import java.util.GregorianCalendar
+import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.round
@@ -57,6 +58,14 @@ class MedtrumPump @Inject constructor(
sp.putInt(R.string.key_pump_state, value.state.toInt())
}
+ // Active alarms
+ private var _activeAlarms: EnumSet = EnumSet.noneOf(AlarmState::class.java)
+ var activeAlarms: EnumSet
+ get() = _activeAlarms
+ set(value) {
+ _activeAlarms = value
+ }
+
// Prime progress as state flow
private val _primeProgress = MutableStateFlow(0)
val primeProgressFlow: StateFlow = _primeProgress
@@ -251,6 +260,8 @@ class MedtrumPump @Inject constructor(
_swVersion = sp.getString(R.string.key_sw_version, "")
_patchStartTime = sp.getLong(R.string.key_patch_start_time, 0L)
+ loadActiveAlarms()
+
val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
try {
_actualBasalProfile = Base64.decode(encodedString, Base64.DEFAULT)
@@ -436,8 +447,40 @@ class MedtrumPump @Inject constructor(
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START (FAKE)"
)
}
+
fun temporaryBasalToString(): String {
if (!tempBasalInProgress) return ""
return tempBasalAbsoluteRate.toString() + "U/h"
}
+
+ fun addAlarm(alarm: AlarmState) {
+ activeAlarms.add(alarm)
+ saveActiveAlarms()
+ }
+
+ fun removeAlarm(alarm: AlarmState) {
+ activeAlarms.remove(alarm)
+ saveActiveAlarms()
+ }
+
+ fun clearAlarmState() {
+ activeAlarms.clear()
+ saveActiveAlarms()
+ }
+
+ private fun saveActiveAlarms() {
+ val alarmsStr = activeAlarms.joinToString(separator = ",") { it.name }
+ sp.putString(R.string.key_active_alarms, alarmsStr)
+ }
+
+ private fun loadActiveAlarms() {
+ val alarmsStr = sp.getString(R.string.key_active_alarms, "")
+ if (alarmsStr.isNullOrEmpty()) {
+ activeAlarms = EnumSet.noneOf(AlarmState::class.java)
+ } else {
+ activeAlarms = alarmsStr.split(",")
+ .mapNotNull { AlarmState.values().find { alarm -> alarm.name == it } }
+ .let { EnumSet.copyOf(it) }
+ }
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/AlarmState.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/AlarmState.kt
new file mode 100644
index 0000000000..392bf85dc3
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/AlarmState.kt
@@ -0,0 +1,23 @@
+package info.nightscout.pump.medtrum.comm.enums
+
+enum class AlarmState {
+ NONE,
+ PUMP_LOW_BATTERY, // Mapped from error flag 1
+ PUMP_LOW_RESERVOIR, // Mapped from error flag 2
+ PUMP_EXPIRES_SOON, // Mapped from error flag 3
+ LOWBG_SUSPENDED, // Mapped from pump status 64
+ LOWBG_SUSPENDED2, // Mapped from pump status 65
+ AUTO_SUSPENDED, // Mapped from pump status 66
+ HMAX_SUSPENDED, // Mapped from pump status 67
+ DMAX_SUSPENDED, // Mapped from pump status 68
+ SUSPENDED, // Mapped from pump status 69
+ PAUSED, // Mapped from pump status 70
+ OCCLUSION, // Mapped from pump status 96
+ EXPIRED, // Mapped from pump status 97
+ RESERVOIR_EMPTY, // Mapped from pump status 98
+ PATCH_FAULT, // Mapped from pump status 99
+ PATCH_FAULT2, // Mapped from pump status 100
+ BASE_FAULT, // Mapped from pump status 101
+ BATTERY_OUT, // Mapped from pump status 102
+ NO_CALIBRATION // Mapped from pump status 103
+}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
index 1072086ca9..4784da2696 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/NotificationPacket.kt
@@ -2,6 +2,7 @@ package info.nightscout.pump.medtrum.comm.packets
import dagger.android.HasAndroidInjector
import info.nightscout.pump.medtrum.MedtrumPump
+import info.nightscout.pump.medtrum.comm.enums.AlarmState
import info.nightscout.pump.medtrum.comm.enums.BasalType
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.extension.toInt
@@ -71,7 +72,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
if (state != medtrumPump.pumpState) {
aapsLogger.debug(LTag.PUMPCOMM, "State changed from ${medtrumPump.pumpState} to $state")
medtrumPump.pumpState = state
- }
+ }
if (notification.size > NOTIF_STATE_END) {
handleMaskedMessage(notification.copyOfRange(NOTIF_STATE_END, notification.size))
@@ -127,7 +128,7 @@ class NotificationPacket(val injector: HasAndroidInjector) {
// Don't spam with basal updates here, only if the running basal rate has changed, or a new basal is set
if (medtrumPump.lastBasalRate != basalRate || medtrumPump.lastBasalStartTime != basalStartTime) {
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
- }
+ }
offset += 12
}
@@ -178,11 +179,26 @@ class NotificationPacket(val injector: HasAndroidInjector) {
}
if (fieldMask and MASK_ALARM != 0) {
- aapsLogger.debug(LTag.PUMPCOMM, "Alarm notification received")
- // Set only flags here, Alarms will be picked up by the state change
- medtrumPump.alarmFlags = data.copyOfRange(offset, offset + 2).toInt()
- medtrumPump.alarmParameter = data.copyOfRange(offset + 2, offset + 4).toInt()
- aapsLogger.debug(LTag.PUMPCOMM, "Alarm flags: ${medtrumPump.alarmFlags}, alarm parameter: ${medtrumPump.alarmParameter}")
+ val alarmFlags = data.copyOfRange(offset, offset + 2).toInt()
+ val alarmParameter = data.copyOfRange(offset + 2, offset + 4).toInt()
+ aapsLogger.debug(LTag.PUMPCOMM, "Alarm notification received, Alarm flags: $alarmFlags, alarm parameter: $alarmParameter")
+
+ // If no alarm, clear activeAlarm list
+ if (alarmFlags == 0 && medtrumPump.activeAlarms.isNotEmpty()) {
+ medtrumPump.clearAlarmState()
+ } else if (alarmFlags != 0) {
+ // Check each alarm bit
+ for (i in 0..3) { // Only the first 3 flags are interesting for us, the rest we will get from the pump state
+ val alarmState = AlarmState.values()[i]
+ if ((alarmFlags shr i) and 1 != 0) {
+ // If the alarm bit is set, add the corresponding alarm to activeAlarms
+ medtrumPump.addAlarm(alarmState)
+ } else if (medtrumPump.activeAlarms.contains(alarmState)) {
+ // If the alarm bit is not set, and the corresponding alarm is in activeAlarms, remove it
+ medtrumPump.removeAlarm(alarmState)
+ }
+ }
+ }
offset += 4
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 39f84d208f..233c63449f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -22,6 +22,7 @@ import info.nightscout.pump.medtrum.MedtrumPlugin
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
+import info.nightscout.pump.medtrum.comm.enums.AlarmState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.comm.packets.*
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
@@ -129,81 +130,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}, fabricPrivacy::logException)
scope.launch {
medtrumPump.pumpStateFlow.collect { state ->
- when (state) {
- MedtrumPumpState.NONE,
- MedtrumPumpState.IDLE,
- MedtrumPumpState.FILLED,
- MedtrumPumpState.PRIMING,
- MedtrumPumpState.PRIMED,
- MedtrumPumpState.EJECTING,
- MedtrumPumpState.EJECTED,
- MedtrumPumpState.STOPPED -> {
- rxBus.send(EventDismissNotification(Notification.PUMP_ERROR))
- rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
- uiInteraction.addNotification(
- Notification.PATCH_NOT_ACTIVE,
- rh.gs(R.string.patch_not_active),
- Notification.URGENT,
- )
- medtrumPump.setFakeTBRIfNeeded()
- }
-
- MedtrumPumpState.ACTIVE,
- MedtrumPumpState.ACTIVE_ALT -> {
- rxBus.send(EventDismissNotification(Notification.PATCH_NOT_ACTIVE))
- rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
- }
-
- MedtrumPumpState.LOWBG_SUSPENDED,
- MedtrumPumpState.LOWBG_SUSPENDED2,
- MedtrumPumpState.AUTO_SUSPENDED,
- MedtrumPumpState.SUSPENDED,
- MedtrumPumpState.PAUSED -> {
- uiInteraction.addNotification(
- Notification.PUMP_SUSPENDED,
- rh.gs(R.string.pump_is_suspended),
- Notification.NORMAL,
- )
- // Pump will report proper TBR for this
- }
-
- MedtrumPumpState.HMAX_SUSPENDED -> {
- uiInteraction.addNotification(
- Notification.PUMP_SUSPENDED,
- rh.gs(R.string.pump_is_suspended_hour_max),
- Notification.NORMAL,
- )
- // Pump will report proper TBR for this
- }
- MedtrumPumpState.DMAX_SUSPENDED -> {
- uiInteraction.addNotification(
- Notification.PUMP_SUSPENDED,
- rh.gs(R.string.pump_is_suspended_day_max),
- Notification.NORMAL,
- )
- // Pump will report proper TBR for this
- }
-
- MedtrumPumpState.OCCLUSION,
- MedtrumPumpState.EXPIRED,
- MedtrumPumpState.RESERVOIR_EMPTY,
- MedtrumPumpState.PATCH_FAULT,
- MedtrumPumpState.PATCH_FAULT2,
- MedtrumPumpState.BASE_FAULT,
- MedtrumPumpState.BATTERY_OUT,
- MedtrumPumpState.NO_CALIBRATION -> {
- rxBus.send(EventDismissNotification(Notification.PATCH_NOT_ACTIVE))
- rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
- // Pump suspended due to error, show error!
- uiInteraction.addNotificationWithSound(
- Notification.PUMP_ERROR,
- rh.gs(R.string.pump_error, state.toString()),
- Notification.URGENT,
- info.nightscout.core.ui.R.raw.alarm
- )
- medtrumPump.setFakeTBRIfNeeded()
- }
- }
+ handlePumpStateUpdate(state)
}
}
@@ -284,31 +211,37 @@ class MedtrumService : DaggerService(), BLECommCallback {
fun clearAlarms(): Boolean {
var result = true
- when (medtrumPump.pumpState) {
- MedtrumPumpState.HMAX_SUSPENDED -> {
- result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, ALARM_HOURLY_MAX_CLEAR_CODE))
- }
- MedtrumPumpState.DMAX_SUSPENDED -> {
- result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, ALARM_DAILY_MAX_CLEAR_CODE))
- }
- else -> {
- // Do nothing
- // TODO: Remove me before release!!!
- // Try to brute force the commands
- aapsLogger.warn(LTag.PUMPCOMM, "Trying to clear alarms brutus!")
- for (i in 0..100) {
- result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, i))
- if (result) {
- aapsLogger.warn(LTag.PUMPCOMM, "Alarm cleared: $i")
- break
+ if (medtrumPump.activeAlarms.isNotEmpty()) {
+ when (medtrumPump.pumpState) {
+ MedtrumPumpState.HMAX_SUSPENDED -> {
+ result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, ALARM_HOURLY_MAX_CLEAR_CODE))
+ }
+
+ MedtrumPumpState.DMAX_SUSPENDED -> {
+ result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, ALARM_DAILY_MAX_CLEAR_CODE))
+ }
+
+ else -> {
+ // TODO: Remove me before release!!!
+ // Try to brute force the commands
+ aapsLogger.warn(LTag.PUMPCOMM, "Trying to clear alarms brutus!")
+ for (i in 0..100) {
+ result = sendPacketAndGetResponse(ClearPumpAlarmPacket(injector, i))
+ if (result) {
+ aapsLogger.warn(LTag.PUMPCOMM, "Alarm cleared: $i")
+ break
+ }
}
}
}
+
}
// Resume suspended pump
- // TODO: We might not want to do this for alarms which don't suspend the pump
+ if (medtrumPump.pumpState in listOf(MedtrumPumpState.LOWBG_SUSPENDED, MedtrumPumpState.PAUSED)) {
+ if (result) result = sendPacketAndGetResponse(ResumePumpPacket(injector))
+ }
if (result) result = sendPacketAndGetResponse(ResumePumpPacket(injector))
-
+
return result
}
@@ -443,6 +376,112 @@ class MedtrumService : DaggerService(), BLECommCallback {
return result
}
+ private fun handlePumpStateUpdate(state: MedtrumPumpState) {
+ // Map the pump state to an alarm state and add it to the active alarms
+ val alarmState = when (state) {
+ MedtrumPumpState.NONE -> AlarmState.NONE
+ MedtrumPumpState.LOWBG_SUSPENDED -> AlarmState.LOWBG_SUSPENDED
+ MedtrumPumpState.LOWBG_SUSPENDED2 -> AlarmState.LOWBG_SUSPENDED2
+ MedtrumPumpState.AUTO_SUSPENDED -> AlarmState.AUTO_SUSPENDED
+ MedtrumPumpState.HMAX_SUSPENDED -> AlarmState.HMAX_SUSPENDED
+ MedtrumPumpState.DMAX_SUSPENDED -> AlarmState.DMAX_SUSPENDED
+ MedtrumPumpState.SUSPENDED -> AlarmState.SUSPENDED
+ MedtrumPumpState.PAUSED -> AlarmState.PAUSED
+ MedtrumPumpState.OCCLUSION -> AlarmState.OCCLUSION
+ MedtrumPumpState.EXPIRED -> AlarmState.EXPIRED
+ MedtrumPumpState.RESERVOIR_EMPTY -> AlarmState.RESERVOIR_EMPTY
+ MedtrumPumpState.PATCH_FAULT -> AlarmState.PATCH_FAULT
+ MedtrumPumpState.PATCH_FAULT2 -> AlarmState.PATCH_FAULT2
+ MedtrumPumpState.BASE_FAULT -> AlarmState.BASE_FAULT
+ MedtrumPumpState.BATTERY_OUT -> AlarmState.BATTERY_OUT
+ MedtrumPumpState.NO_CALIBRATION -> AlarmState.NO_CALIBRATION
+ else -> null
+ }
+ if (alarmState != null && alarmState != AlarmState.NONE) {
+ medtrumPump.addAlarm(alarmState)
+ }
+
+ // Map the pump state to a notification
+ when (state) {
+ MedtrumPumpState.NONE,
+ MedtrumPumpState.IDLE,
+ MedtrumPumpState.FILLED,
+ MedtrumPumpState.PRIMING,
+ MedtrumPumpState.PRIMED,
+ MedtrumPumpState.EJECTING,
+ MedtrumPumpState.EJECTED,
+ MedtrumPumpState.STOPPED -> {
+ rxBus.send(EventDismissNotification(Notification.PUMP_ERROR))
+ rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
+ uiInteraction.addNotification(
+ Notification.PATCH_NOT_ACTIVE,
+ rh.gs(R.string.patch_not_active),
+ Notification.URGENT,
+ )
+ medtrumPump.setFakeTBRIfNeeded()
+ medtrumPump.clearAlarmState()
+ }
+
+ MedtrumPumpState.ACTIVE,
+ MedtrumPumpState.ACTIVE_ALT -> {
+ rxBus.send(EventDismissNotification(Notification.PATCH_NOT_ACTIVE))
+ rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
+ medtrumPump.clearAlarmState()
+ }
+
+ MedtrumPumpState.LOWBG_SUSPENDED,
+ MedtrumPumpState.LOWBG_SUSPENDED2,
+ MedtrumPumpState.AUTO_SUSPENDED,
+ MedtrumPumpState.SUSPENDED,
+ MedtrumPumpState.PAUSED -> {
+ uiInteraction.addNotification(
+ Notification.PUMP_SUSPENDED,
+ rh.gs(R.string.pump_is_suspended),
+ Notification.NORMAL,
+ )
+ // Pump will report proper TBR for this
+ }
+
+ MedtrumPumpState.HMAX_SUSPENDED -> {
+ uiInteraction.addNotification(
+ Notification.PUMP_SUSPENDED,
+ rh.gs(R.string.pump_is_suspended_hour_max),
+ Notification.NORMAL,
+ )
+ // Pump will report proper TBR for this
+ }
+
+ MedtrumPumpState.DMAX_SUSPENDED -> {
+ uiInteraction.addNotification(
+ Notification.PUMP_SUSPENDED,
+ rh.gs(R.string.pump_is_suspended_day_max),
+ Notification.NORMAL,
+ )
+ // Pump will report proper TBR for this
+ }
+
+ MedtrumPumpState.OCCLUSION,
+ MedtrumPumpState.EXPIRED,
+ MedtrumPumpState.RESERVOIR_EMPTY,
+ MedtrumPumpState.PATCH_FAULT,
+ MedtrumPumpState.PATCH_FAULT2,
+ MedtrumPumpState.BASE_FAULT,
+ MedtrumPumpState.BATTERY_OUT,
+ MedtrumPumpState.NO_CALIBRATION -> {
+ rxBus.send(EventDismissNotification(Notification.PATCH_NOT_ACTIVE))
+ rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
+ // Pump suspended due to error, show error!
+ uiInteraction.addNotificationWithSound(
+ Notification.PUMP_ERROR,
+ rh.gs(R.string.pump_error, state.toString()),
+ Notification.URGENT,
+ info.nightscout.core.ui.R.raw.alarm
+ )
+ medtrumPump.setFakeTBRIfNeeded()
+ }
+ }
+ }
+
/** BLECommCallbacks */
override fun onBLEConnected() {
aapsLogger.debug(LTag.PUMPCOMM, "<<<<< onBLEConnected")
@@ -586,7 +625,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
if (mPacket?.handleResponse(data) == true) {
// Succes!
responseHandled = true
- responseSuccess = true
+ responseSuccess = true
toState(GetDeviceTypeState())
} else if (mPacket?.failed == true) {
// Failure
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
index 98c99febd8..81567bfa42 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumOverviewFragment.kt
@@ -49,6 +49,7 @@ class MedtrumOverviewFragment : MedtrumBaseFragment Unit
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index 85a2db7fba..e7a64049fd 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -10,6 +10,7 @@ import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.pump.medtrum.MedtrumPump
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.ConnectionState
+import info.nightscout.pump.medtrum.comm.enums.AlarmState
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
@@ -168,8 +169,8 @@ class MedtrumOverviewViewModel @Inject constructor(
_lastBolus.postValue("")
}
- // TODO: Update these values
- // _activeAlarms.postValue(rh.gs(R.string.active_alarms, pump.activeAlarms))
+ val activeAlarmStrings = medtrumPump.activeAlarms.map { alarmStateToString(it) }
+ _activeAlarms.postValue(activeAlarmStrings.joinToString("\n"))
_pumpType.postValue(medtrumPump.deviceType.toString())
_fwVersion.postValue(medtrumPump.swVersion)
_patchNo.postValue(medtrumPump.patchId.toString())
@@ -181,5 +182,30 @@ class MedtrumOverviewViewModel @Inject constructor(
_patchExpiry.postValue(rh.gs(R.string.expiry_not_enabled))
}
}
+
+ private fun alarmStateToString(alarmState: AlarmState): String {
+ val stringId = when (alarmState) {
+ AlarmState.NONE -> R.string.alarm_none
+ AlarmState.PUMP_LOW_BATTERY -> R.string.alarm_pump_low_battery
+ AlarmState.PUMP_LOW_RESERVOIR -> R.string.alarm_pump_low_reservoir
+ AlarmState.PUMP_EXPIRES_SOON -> R.string.alarm_pump_expires_soon
+ AlarmState.LOWBG_SUSPENDED -> R.string.alarm_lowbg_suspended
+ AlarmState.LOWBG_SUSPENDED2 -> R.string.alarm_lowbg_suspended2
+ AlarmState.AUTO_SUSPENDED -> R.string.alarm_auto_suspended
+ AlarmState.HMAX_SUSPENDED -> R.string.alarm_hmax_suspended
+ AlarmState.DMAX_SUSPENDED -> R.string.alarm_dmax_suspended
+ AlarmState.SUSPENDED -> R.string.alarm_suspended
+ AlarmState.PAUSED -> R.string.alarm_paused
+ AlarmState.OCCLUSION -> R.string.alarm_occlusion
+ AlarmState.EXPIRED -> R.string.alarm_expired
+ AlarmState.RESERVOIR_EMPTY -> R.string.alarm_reservoir_empty
+ AlarmState.PATCH_FAULT -> R.string.alarm_patch_fault
+ AlarmState.PATCH_FAULT2 -> R.string.alarm_patch_fault2
+ AlarmState.BASE_FAULT -> R.string.alarm_base_fault
+ AlarmState.BATTERY_OUT -> R.string.alarm_battery_out
+ AlarmState.NO_CALIBRATION -> R.string.alarm_no_calibration
+ }
+ return rh.gs(stringId)
+ }
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 506658da45..53ee9e747b 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -9,6 +9,7 @@
medtrumpump_settings
pump_state
+ active_alarms
last_connection
last_bolus_time
last_bolus_amount
@@ -52,6 +53,27 @@
Requested by user
Not enabled
+
+ None
+ Pump low battery
+ Pump low reservoir
+ Pump expires soon
+ Low BG suspended
+ Low BG suspended 2
+ Auto suspended
+ hourly max suspended
+ daily max suspended
+ Suspended
+ Paused
+ Occlusion
+ Expired
+ Reservoir empty
+ Patch fault
+ Patch fault 2
+ Base fault
+ Battery out
+ No calibration
+
Discard/Change Patch
Next
From 2302711cdffba23322518b50a9e62ce931bfeddc Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 20 Jun 2023 09:30:41 +0200
Subject: [PATCH 046/116] Additional Notifications, handling sync of percentage
TBR
---
.../interfaces/pump/defs/PumpType.kt | 3 +-
.../nightscout/core/pump/PumpTypeExtension.kt | 2 +
.../entities/embedments/InterfaceIDs.kt | 1 +
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 4 +-
.../nightscout/pump/medtrum/MedtrumPump.kt | 56 +++++++++++++----
.../pump/medtrum/comm/enums/BolusType.kt | 4 +-
.../medtrum/comm/packets/ActivatePacket.kt | 4 +-
.../comm/packets/CancelTempBasalPacket.kt | 2 +-
.../medtrum/comm/packets/GetRecordPacket.kt | 60 +++++++++++++++----
.../pump/medtrum/services/MedtrumService.kt | 19 +++++-
.../ui/viewmodel/MedtrumOverviewViewModel.kt | 35 ++---------
pump/medtrum/src/main/res/values/strings.xml | 1 +
12 files changed, 130 insertions(+), 61 deletions(-)
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
index 68dbf1277d..3bd481629c 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpType.kt
@@ -412,7 +412,8 @@ enum class PumpType {
isPatchPump = true,
maxReservoirReading = 400,
source = Source.Medtrum
- );
+ ),
+ MEDTRUM_UNTESTED(description = "Medtrum untested", model = "untested", parent = MEDTRUM_NANO);
val description: String
var manufacturer: ManufacturerType? = null
diff --git a/core/main/src/main/java/info/nightscout/core/pump/PumpTypeExtension.kt b/core/main/src/main/java/info/nightscout/core/pump/PumpTypeExtension.kt
index 8a0b120cc1..321365cba4 100644
--- a/core/main/src/main/java/info/nightscout/core/pump/PumpTypeExtension.kt
+++ b/core/main/src/main/java/info/nightscout/core/pump/PumpTypeExtension.kt
@@ -60,6 +60,7 @@ fun PumpType.Companion.fromDbPumpType(pt: InterfaceIDs.PumpType): PumpType =
InterfaceIDs.PumpType.DIACONN_G8 -> PumpType.DIACONN_G8
InterfaceIDs.PumpType.EOPATCH2 -> PumpType.EOFLOW_EOPATCH2
InterfaceIDs.PumpType.MEDTRUM -> PumpType.MEDTRUM_NANO
+ InterfaceIDs.PumpType.MEDTRUM_UNTESTED -> PumpType.MEDTRUM_UNTESTED
InterfaceIDs.PumpType.CACHE -> PumpType.CACHE
}
@@ -119,5 +120,6 @@ fun PumpType.toDbPumpType(): InterfaceIDs.PumpType =
PumpType.DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8
PumpType.EOFLOW_EOPATCH2 -> InterfaceIDs.PumpType.EOPATCH2
PumpType.MEDTRUM_NANO -> InterfaceIDs.PumpType.MEDTRUM
+ PumpType.MEDTRUM_UNTESTED -> InterfaceIDs.PumpType.MEDTRUM_UNTESTED
PumpType.CACHE -> InterfaceIDs.PumpType.CACHE
}
diff --git a/database/entities/src/main/java/info/nightscout/database/entities/embedments/InterfaceIDs.kt b/database/entities/src/main/java/info/nightscout/database/entities/embedments/InterfaceIDs.kt
index a10a7740cd..0a244aa3c6 100644
--- a/database/entities/src/main/java/info/nightscout/database/entities/embedments/InterfaceIDs.kt
+++ b/database/entities/src/main/java/info/nightscout/database/entities/embedments/InterfaceIDs.kt
@@ -44,6 +44,7 @@ data class InterfaceIDs(
DIACONN_G8,
EOPATCH2,
MEDTRUM,
+ MEDTRUM_UNTESTED,
USER,
CACHE;
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index ca1cecc7b3..a7b4099c95 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -363,7 +363,7 @@ import kotlin.math.round
}
override fun model(): PumpType {
- return medtrumPump.pumpType
+ return medtrumPump.pumpType()
}
override fun serialNumber(): String {
@@ -371,7 +371,7 @@ import kotlin.math.round
}
override val pumpDescription: PumpDescription
- get() = PumpDescription(medtrumPump.pumpType)
+ get() = PumpDescription(medtrumPump.pumpType())
override fun shortStatus(veryShort: Boolean): String {
var ret = ""
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
index 381ec89b88..6783927607 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPump.kt
@@ -15,6 +15,7 @@ import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
@@ -28,6 +29,7 @@ import kotlin.math.round
@Singleton
class MedtrumPump @Inject constructor(
private val aapsLogger: AAPSLogger,
+ private val rh: ResourceHelper,
private val sp: SP,
private val dateUtil: DateUtil,
private val pumpSync: PumpSync,
@@ -168,7 +170,7 @@ class MedtrumPump @Inject constructor(
sp.putLong(R.string.key_last_connection, value)
}
- private var _deviceType: Int = 0 // As reported by pump
+ private var _deviceType: Int = 80 // As reported by pump
var deviceType: Int
get() = _deviceType
set(value) {
@@ -196,16 +198,10 @@ class MedtrumPump @Inject constructor(
val pumpSN: Long
get() = _pumpSN
- val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on deviceType from pump
-
var lastTimeReceivedFromPump = 0L // Time in ms! // TODO: Consider removing as is not used?
var suspendTime = 0L // Time in ms!
var patchAge = 0L // Time in seconds?! // TODO: Not used
-
- var alarmFlags = 0
- var alarmParameter = 0
-
// bolus status
var bolusingTreatment: EventOverviewBolusProgress.Treatment? = null // actually delivered treatment
var bolusAmountToBeDelivered = 0.0 // amount to be delivered
@@ -270,6 +266,12 @@ class MedtrumPump @Inject constructor(
}
}
+ fun pumpType(): PumpType =
+ when(deviceType) {
+ 80, 88 -> PumpType.MEDTRUM_NANO
+ else -> PumpType.MEDTRUM_UNTESTED
+ }
+
fun loadUserSettingsFromSP() {
desiredPatchExpiration = sp.getBoolean(info.nightscout.pump.medtrum.R.string.key_patch_expiration, false)
val alarmSettingCode = sp.getString(info.nightscout.pump.medtrum.R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code.toString()).toByte()
@@ -356,7 +358,7 @@ class MedtrumPump @Inject constructor(
LTag.PUMP,
"handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + "receivedTime: $receivedTime"
)
- @Suppress("UNNECESSARY_SAFE_CALL") // Safe call to allow mocks to retun null
+ @Suppress("UNNECESSARY_SAFE_CALL") // Safe call to allow mocks to return null
val expectedTemporaryBasal = pumpSync.expectedPumpState()?.temporaryBasal
if (basalType.isTempBasal() && expectedTemporaryBasal?.pumpId != basalStartTime) {
// Note: temporaryBasalInfo will be removed from temporaryBasalStorage after this call
@@ -364,14 +366,19 @@ class MedtrumPump @Inject constructor(
// If duration is unknown, no way to get it now, set patch lifetime as duration
val duration = temporaryBasalInfo?.duration ?: T.mins(FAKE_TBR_LENGTH).msecs()
+ val adjustedBasalRate = if (basalType == BasalType.ABSOLUTE_TEMP) {
+ basalRate
+ } else {
+ (basalRate / baseBasalRate) * 100 // calculate the percentage of the original basal rate
+ }
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime,
- rate = basalRate, // TODO: Support percent here, this will break things? Check if this is correct
+ rate = adjustedBasalRate,
duration = duration,
isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
type = temporaryBasalInfo?.type,
pumpId = basalStartTime,
- pumpType = pumpType,
+ pumpType = pumpType(),
pumpSerial = pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@@ -386,7 +393,7 @@ class MedtrumPump @Inject constructor(
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime,
- pumpType = pumpType,
+ pumpType = pumpType(),
pumpSerial = pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@@ -439,7 +446,7 @@ class MedtrumPump @Inject constructor(
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = dateUtil.now(),
- pumpType = pumpType,
+ pumpType = pumpType(),
pumpSerial = pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@@ -468,6 +475,31 @@ class MedtrumPump @Inject constructor(
saveActiveAlarms()
}
+ fun alarmStateToString(alarmState: AlarmState): String {
+ val stringId = when (alarmState) {
+ AlarmState.NONE -> R.string.alarm_none
+ AlarmState.PUMP_LOW_BATTERY -> R.string.alarm_pump_low_battery
+ AlarmState.PUMP_LOW_RESERVOIR -> R.string.alarm_pump_low_reservoir
+ AlarmState.PUMP_EXPIRES_SOON -> R.string.alarm_pump_expires_soon
+ AlarmState.LOWBG_SUSPENDED -> R.string.alarm_lowbg_suspended
+ AlarmState.LOWBG_SUSPENDED2 -> R.string.alarm_lowbg_suspended2
+ AlarmState.AUTO_SUSPENDED -> R.string.alarm_auto_suspended
+ AlarmState.HMAX_SUSPENDED -> R.string.alarm_hmax_suspended
+ AlarmState.DMAX_SUSPENDED -> R.string.alarm_dmax_suspended
+ AlarmState.SUSPENDED -> R.string.alarm_suspended
+ AlarmState.PAUSED -> R.string.alarm_paused
+ AlarmState.OCCLUSION -> R.string.alarm_occlusion
+ AlarmState.EXPIRED -> R.string.alarm_expired
+ AlarmState.RESERVOIR_EMPTY -> R.string.alarm_reservoir_empty
+ AlarmState.PATCH_FAULT -> R.string.alarm_patch_fault
+ AlarmState.PATCH_FAULT2 -> R.string.alarm_patch_fault2
+ AlarmState.BASE_FAULT -> R.string.alarm_base_fault
+ AlarmState.BATTERY_OUT -> R.string.alarm_battery_out
+ AlarmState.NO_CALIBRATION -> R.string.alarm_no_calibration
+ }
+ return rh.gs(stringId)
+ }
+
private fun saveActiveAlarms() {
val alarmsStr = activeAlarms.joinToString(separator = ",") { it.name }
sp.putString(R.string.key_active_alarms, alarmsStr)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
index ef245d1805..7bf88c9f53 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/enums/BolusType.kt
@@ -3,6 +3,6 @@ package info.nightscout.pump.medtrum.comm.enums
enum class BolusType {
NONE,
NORMAL,
- EXTEND,
- COMBINATION;
+ EXTENDED,
+ COMBI;
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
index 2eaeb17b86..cfe94aee60 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/ActivatePacket.kt
@@ -107,13 +107,13 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
pumpSync.insertTherapyEventIfNewWithTimestamp(
timestamp = System.currentTimeMillis(),
type = DetailedBolusInfo.EventType.CANNULA_CHANGE,
- pumpType = medtrumPump.pumpType,
+ pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
pumpSync.insertTherapyEventIfNewWithTimestamp(
timestamp = System.currentTimeMillis(),
type = DetailedBolusInfo.EventType.INSULIN_CHANGE,
- pumpType = medtrumPump.pumpType,
+ pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
index c3067ed501..8d0ebd477b 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/CancelTempBasalPacket.kt
@@ -53,7 +53,7 @@ class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(inject
pumpSync.syncStopTemporaryBasalWithPumpId(
timestamp = basalStartTime, // Time of normal basal start = time of tbr end
endPumpId = basalStartTime,
- pumpType = medtrumPump.pumpType,
+ pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
index 265e7b3ae9..d6a29a66e3 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -94,7 +94,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
val bolusNormalAmount = data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 10).toInt() * 0.05
val bolusNormalDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 10, RESP_RECORD_DATA_START + 12).toInt() * 0.05
val bolusExtendedAmount = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 14).toInt() * 0.05
- val bolusExtendedDuration = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toInt()
+ val bolusExtendedDuration = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toLong() * 1000
val bolusExtendedDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 16, RESP_RECORD_DATA_START + 18).toInt() * 0.05
val bolusCarb = data.copyOfRange(RESP_RECORD_DATA_START + 18, RESP_RECORD_DATA_START + 20).toInt()
val bolusGlucose = data.copyOfRange(RESP_RECORD_DATA_START + 20, RESP_RECORD_DATA_START + 22).toInt()
@@ -114,7 +114,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
amount = bolusNormalDelivered,
type = detailedBolusInfo?.bolusType,
pumpId = bolusStartTime,
- pumpType = medtrumPump.pumpType,
+ pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@@ -129,12 +129,54 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
medtrumPump.lastBolusTime = bolusStartTime
medtrumPump.lastBolusAmount = bolusNormalDelivered
}
- } else {
- // TODO: at least record the bolus
+ } else if (bolusType == BolusType.EXTENDED) {
+ val newRecord = pumpSync.syncExtendedBolusWithPumpId(
+ timestamp = bolusStartTime,
+ amount = bolusExtendedDelivered,
+ duration = bolusExtendedDuration,
+ isEmulatingTB = false,
+ pumpId = bolusStartTime,
+ pumpType = medtrumPump.pumpType(),
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "from record: ${if (newRecord) "**NEW** " else ""}EVENT EXTENDED BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U "
+ )
+ } else if (bolusType == BolusType.COMBI) {
+ // Note, this should never happen, as we don't use combo bolus
+ val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(bolusStartTime, bolusNormalDelivered)
+ val newRecord = pumpSync.syncBolusWithPumpId(
+ timestamp = bolusStartTime,
+ amount = bolusNormalDelivered,
+ type = detailedBolusInfo?.bolusType,
+ pumpId = bolusStartTime,
+ pumpType = medtrumPump.pumpType(),
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ pumpSync.syncExtendedBolusWithPumpId(
+ timestamp = bolusStartTime,
+ amount = bolusExtendedDelivered,
+ duration = bolusExtendedDuration,
+ isEmulatingTB = false,
+ pumpId = bolusStartTime,
+ pumpType = medtrumPump.pumpType(),
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
aapsLogger.error(
LTag.PUMPCOMM,
- "from record: EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) " + "Bolus type: $bolusType not supported"
+ "from record: ${if (newRecord) "**NEW** " else ""}EVENT COMBI BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U Extended: ${bolusExtendedDelivered} THIS SHOULD NOT HAPPEN!!!"
)
+ if (!newRecord && detailedBolusInfo != null) {
+ // detailedInfo can be from another similar record. Reinsert
+ detailedBolusInfoStorage.add(detailedBolusInfo)
+ }
+ if (bolusStartTime > medtrumPump.lastBolusTime) {
+ medtrumPump.lastBolusTime = bolusStartTime
+ medtrumPump.lastBolusAmount = bolusNormalDelivered
+ }
+ } else {
+ aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD: Unknown bolus type: $bolusType")
}
}
@@ -171,7 +213,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
type = PumpSync.TemporaryBasalType.NORMAL,
pumpId = basalStartTime,
- pumpType = medtrumPump.pumpType,
+ pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@@ -183,7 +225,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
pumpSync.syncStopTemporaryBasalWithPumpId(
timestamp = basalEndTime,
endPumpId = basalEndTime,
- pumpType = medtrumPump.pumpType,
+ pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.warn(
@@ -202,7 +244,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime,
- pumpType = medtrumPump.pumpType,
+ pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@@ -210,11 +252,9 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT SUSPEND: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
"Rate: $basalRate Duration: ${duration}"
)
-
}
else -> {
aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Unknown basal type: $basalType")
- // TODO: Error warning
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 233c63449f..39c55b5cca 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -15,6 +15,7 @@ import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.PumpSync
+import info.nightscout.interfaces.pump.defs.PumpType
import info.nightscout.interfaces.queue.Callback
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
@@ -473,7 +474,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Pump suspended due to error, show error!
uiInteraction.addNotificationWithSound(
Notification.PUMP_ERROR,
- rh.gs(R.string.pump_error, state.toString()),
+ rh.gs(R.string.pump_error, alarmState?.let { medtrumPump.alarmStateToString(it) }),
Notification.URGENT,
info.nightscout.core.ui.R.raw.alarm
)
@@ -626,7 +627,21 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Succes!
responseHandled = true
responseSuccess = true
- toState(GetDeviceTypeState())
+ // Check if we have a supported pump
+ if (medtrumPump.pumpType() == PumpType.MEDTRUM_UNTESTED) {
+ // Throw error
+ aapsLogger.error(LTag.PUMPCOMM, "Unsupported pump type")
+ uiInteraction.addNotificationWithSound(
+ Notification.PUMP_ERROR,
+ rh.gs(R.string.pump_unsupported, medtrumPump.deviceType),
+ Notification.URGENT,
+ info.nightscout.core.ui.R.raw.alarm
+ )
+ bleComm.disconnect("Unsupported pump")
+ toState(IdleState())
+ } else {
+ toState(GetDeviceTypeState())
+ }
} else if (mPacket?.failed == true) {
// Failure
responseHandled = true
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
index e7a64049fd..d86a3efb25 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/MedtrumOverviewViewModel.kt
@@ -150,9 +150,11 @@ class MedtrumOverviewViewModel @Inject constructor(
fun updateGUI() {
// Update less dynamic values
- val agoMilliseconds = System.currentTimeMillis() - medtrumPump.lastConnection
- val agoMinutes = agoMilliseconds / 1000 / 60
- _lastConnectionMinAgo.postValue(rh.gs(info.nightscout.shared.R.string.minago, agoMinutes))
+ if (medtrumPump.lastConnection != 0L) {
+ val agoMilliseconds = System.currentTimeMillis() - medtrumPump.lastConnection
+ val agoMinutes = agoMilliseconds / 1000 / 60
+ _lastConnectionMinAgo.postValue(rh.gs(info.nightscout.shared.R.string.minago, agoMinutes))
+ }
if (medtrumPump.lastBolusTime != 0L) {
val agoMilliseconds = System.currentTimeMillis() - medtrumPump.lastBolusTime
val agoHours = agoMilliseconds.toDouble() / 60.0 / 60.0 / 1000.0
@@ -169,7 +171,7 @@ class MedtrumOverviewViewModel @Inject constructor(
_lastBolus.postValue("")
}
- val activeAlarmStrings = medtrumPump.activeAlarms.map { alarmStateToString(it) }
+ val activeAlarmStrings = medtrumPump.activeAlarms.map { medtrumPump.alarmStateToString(it) }
_activeAlarms.postValue(activeAlarmStrings.joinToString("\n"))
_pumpType.postValue(medtrumPump.deviceType.toString())
_fwVersion.postValue(medtrumPump.swVersion)
@@ -182,30 +184,5 @@ class MedtrumOverviewViewModel @Inject constructor(
_patchExpiry.postValue(rh.gs(R.string.expiry_not_enabled))
}
}
-
- private fun alarmStateToString(alarmState: AlarmState): String {
- val stringId = when (alarmState) {
- AlarmState.NONE -> R.string.alarm_none
- AlarmState.PUMP_LOW_BATTERY -> R.string.alarm_pump_low_battery
- AlarmState.PUMP_LOW_RESERVOIR -> R.string.alarm_pump_low_reservoir
- AlarmState.PUMP_EXPIRES_SOON -> R.string.alarm_pump_expires_soon
- AlarmState.LOWBG_SUSPENDED -> R.string.alarm_lowbg_suspended
- AlarmState.LOWBG_SUSPENDED2 -> R.string.alarm_lowbg_suspended2
- AlarmState.AUTO_SUSPENDED -> R.string.alarm_auto_suspended
- AlarmState.HMAX_SUSPENDED -> R.string.alarm_hmax_suspended
- AlarmState.DMAX_SUSPENDED -> R.string.alarm_dmax_suspended
- AlarmState.SUSPENDED -> R.string.alarm_suspended
- AlarmState.PAUSED -> R.string.alarm_paused
- AlarmState.OCCLUSION -> R.string.alarm_occlusion
- AlarmState.EXPIRED -> R.string.alarm_expired
- AlarmState.RESERVOIR_EMPTY -> R.string.alarm_reservoir_empty
- AlarmState.PATCH_FAULT -> R.string.alarm_patch_fault
- AlarmState.PATCH_FAULT2 -> R.string.alarm_patch_fault2
- AlarmState.BASE_FAULT -> R.string.alarm_base_fault
- AlarmState.BATTERY_OUT -> R.string.alarm_battery_out
- AlarmState.NO_CALIBRATION -> R.string.alarm_no_calibration
- }
- return rh.gs(stringId)
- }
}
\ No newline at end of file
diff --git a/pump/medtrum/src/main/res/values/strings.xml b/pump/medtrum/src/main/res/values/strings.xml
index 53ee9e747b..ee5e673d94 100644
--- a/pump/medtrum/src/main/res/values/strings.xml
+++ b/pump/medtrum/src/main/res/values/strings.xml
@@ -27,6 +27,7 @@
Medtrum Nano
Medtrum pump settings
Pump error: %1$s !!
+ Pump untested: %1$d! Please contact us at discord or github for support
Pump is suspended
Pump is suspended due to hourly max insulin exceeded
Pump is suspended due to daily max insulin exceeded
From bc8876b6ddacd21db73f2cc00475b45d2168f0b2 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Tue, 20 Jun 2023 12:00:04 +0200
Subject: [PATCH 047/116] BLEComm: Synchronize read and writes better
---
.../pump/medtrum/services/BLEComm.kt | 20 +++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 8a72ae691c..8707aa1309 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -99,6 +99,7 @@ class BLEComm @Inject internal constructor(
private var mWritePackets: WriteCommandPackets? = null
private var mWriteSequenceNumber: Int = 0
private var mReadPacket: ReadDataPacket? = null
+ private val readLock = Any()
private var mDeviceSN: Long = 0
private var mCallback: BLECommCallback? = null
@@ -268,14 +269,16 @@ class BLEComm @Inject internal constructor(
if (characteristic.getUuid() == UUID.fromString(READ_UUID)) {
mCallback?.onNotification(value)
} else if (characteristic.getUuid() == UUID.fromString(WRITE_UUID)) {
- if (mReadPacket == null) {
- mReadPacket = ReadDataPacket(value)
- } else {
- mReadPacket?.addData(value)
- }
- if (mReadPacket?.allDataReceived() == true) {
- mReadPacket?.getData()?.let { mCallback?.onIndication(it) }
- mReadPacket = null
+ synchronized(readLock) {
+ if (mReadPacket == null) {
+ mReadPacket = ReadDataPacket(value)
+ } else {
+ mReadPacket?.addData(value)
+ }
+ if (mReadPacket?.allDataReceived() == true) {
+ mReadPacket?.getData()?.let { mCallback?.onIndication(it) }
+ mReadPacket = null
+ }
}
}
}
@@ -456,6 +459,7 @@ class BLEComm @Inject internal constructor(
mBluetoothGatt?.writeCharacteristic(characteristic)
}
}, WRITE_DELAY_MILLIS)
+ SystemClock.sleep(WRITE_DELAY_MILLIS)
}
private val uartWriteBTGattChar: BluetoothGattCharacteristic
From 17aecd912aea647179242bebe44d8f3a2191dbbb Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 22 Jun 2023 16:02:19 +0200
Subject: [PATCH 048/116] Remove SynchronizePacket from some operations to
improve stability
---
.../pump/medtrum/services/MedtrumService.kt | 25 ++++---------------
1 file changed, 5 insertions(+), 20 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 39c55b5cca..d39a59ed5a 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -174,8 +174,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
}
if (result) result = sendPacketAndGetResponse(StopPatchPacket(injector))
- // Synchronize after deactivation to get update status
- if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
return result
}
@@ -193,19 +191,16 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun loadEvents(): Boolean {
- // Send a poll patch, to workaround connection losses?
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingpumpstatus)))
- var result = sendPacketAndGetResponse(PollPatchPacket(injector))
- // So just do a syncronize to make sure we have the latest data
- if (result) result = sendPacketAndGetResponse(SynchronizePacket(injector))
-
// Sync records (based on the info we have from the sync)
- if (result) result = syncRecords()
+ val result = syncRecords()
if (result) {
aapsLogger.debug(LTag.PUMPCOMM, "Events loaded")
medtrumPump.lastConnection = System.currentTimeMillis()
} else {
- aapsLogger.error(LTag.PUMPCOMM, "Failed to sync records")
+ aapsLogger.error(LTag.PUMPCOMM, "Failed to load events")
+ // TODO: remove me before release
+ fabricPrivacy.logMessage("Medtrum LoadEvents: Failed to load events")
}
return result
}
@@ -235,7 +230,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
}
}
-
}
// Resume suspended pump
if (medtrumPump.pumpState in listOf(MedtrumPumpState.LOWBG_SUSPENDED, MedtrumPumpState.PAUSED)) {
@@ -293,12 +287,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Do not call update status directly, reconnection may be needed
commandQueue.loadEvents(object : Callback() {
override fun run() {
- if (this.result.success == false && isConnected == false) {
- // Reschedule loadEvents when we lost connection during the command
- aapsLogger.warn(LTag.PUMP, "loadEvents failed due to connection loss, rescheduling")
- commandQueue.loadEvents(this)
- return
- }
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus)))
bolusingEvent.percent = 100
}
@@ -366,11 +354,8 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Note: medtrum app fetches all records when they sync?
if (medtrumPump.syncedSequenceNumber < medtrumPump.currentSequenceNumber) {
for (sequence in (medtrumPump.syncedSequenceNumber + 1)..medtrumPump.currentSequenceNumber) {
- // Send a poll patch, to workaround connection losses?
- result = sendPacketAndGetResponse(PollPatchPacket(injector))
+ result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence), COMMAND_SYNC_TIMEOUT_SEC)
SystemClock.sleep(100)
- // Get our record
- if (result) result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence), COMMAND_SYNC_TIMEOUT_SEC)
if (result == false) break
}
}
From e9964604a13579945e5c8eff8c4279d2bed4c74e Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Thu, 22 Jun 2023 18:55:58 +0200
Subject: [PATCH 049/116] Sync bolus initially when bolus command is accepted
by pump
---
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 4 +-
.../medtrum/comm/packets/GetRecordPacket.kt | 40 +++++++++++++------
.../pump/medtrum/services/MedtrumService.kt | 32 +++++++++++++--
3 files changed, 57 insertions(+), 19 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index a7b4099c95..1a466b2f43 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -77,7 +77,6 @@ import kotlin.math.round
private val uiInteraction: UiInteraction,
private val profileFunction: ProfileFunction,
private val pumpSync: PumpSync,
- private val detailedBolusInfoStorage: DetailedBolusInfoStorage,
private val temporaryBasalStorage: TemporaryBasalStorage
) : PumpPluginBase(
PluginDescription()
@@ -233,9 +232,8 @@ import kotlin.math.round
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value()
return if (detailedBolusInfo.insulin > 0 && detailedBolusInfo.carbs == 0.0) {
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Delivering bolus: " + detailedBolusInfo.insulin + "U")
- detailedBolusInfoStorage.add(detailedBolusInfo) // will be picked up on reading history
val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.id)
- val connectionOK = medtrumService?.setBolus(detailedBolusInfo.insulin, t) ?: false
+ val connectionOK = medtrumService?.setBolus(detailedBolusInfo, t) ?: false
val result = PumpEnactResult(injector)
result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep
result.bolusDelivered = t.insulin
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
index d6a29a66e3..99a46174bd 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -107,24 +107,40 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
LTag.PUMPCOMM,
"GetRecordPacket HandleResponse: BOLUS_RECORD: typeAndWizard: $typeAndWizard, bolusCause: $bolusCause, unknown: $unknown, bolusStartTime: $bolusStartTime, " + "bolusNormalAmount: $bolusNormalAmount, bolusNormalDelivered: $bolusNormalDelivered, bolusExtendedAmount: $bolusExtendedAmount, bolusExtendedDuration: $bolusExtendedDuration, " + "bolusExtendedDelivered: $bolusExtendedDelivered, bolusCarb: $bolusCarb, bolusGlucose: $bolusGlucose, bolusIOB: $bolusIOB, unkown1: $unkown1, unkown2: $unkown2, " + "bolusType: $bolusType, bolusWizard: $bolusWizard"
)
+
if (bolusType == BolusType.NORMAL) {
val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(bolusStartTime, bolusNormalDelivered)
- val newRecord = pumpSync.syncBolusWithPumpId(
- timestamp = bolusStartTime,
- amount = bolusNormalDelivered,
- type = detailedBolusInfo?.bolusType,
- pumpId = bolusStartTime,
- pumpType = medtrumPump.pumpType(),
- pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
- )
+ var newRecord = false
+ if (detailedBolusInfo != null) {
+ val success = pumpSync.syncBolusWithTempId(
+ timestamp = bolusStartTime,
+ amount = bolusNormalDelivered,
+ temporaryId = detailedBolusInfo.timestamp,
+ type = detailedBolusInfo.bolusType,
+ pumpId = bolusStartTime,
+ pumpType = medtrumPump.pumpType(),
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ if (success == false) {
+ aapsLogger.warn(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD: Failed to sync bolus with tempId: ${detailedBolusInfo.timestamp}")
+ // detailedInfo can be from another similar record. Reinsert
+ detailedBolusInfoStorage.add(detailedBolusInfo)
+ }
+ } else {
+ newRecord = pumpSync.syncBolusWithPumpId(
+ timestamp = bolusStartTime,
+ amount = bolusNormalDelivered,
+ type = null,
+ pumpId = bolusStartTime,
+ pumpType = medtrumPump.pumpType(),
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ }
+
aapsLogger.debug(
LTag.PUMPCOMM,
"from record: ${if (newRecord) "**NEW** " else ""}EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U "
)
- if (!newRecord && detailedBolusInfo != null) {
- // detailedInfo can be from another similar record. Reinsert
- detailedBolusInfoStorage.add(detailedBolusInfo)
- }
if (bolusStartTime > medtrumPump.lastBolusTime) {
medtrumPump.lastBolusTime = bolusStartTime
medtrumPump.lastBolusAmount = bolusNormalDelivered
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index d39a59ed5a..60d6b5ba8f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -14,6 +14,8 @@ import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
+import info.nightscout.interfaces.pump.DetailedBolusInfo
+import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.defs.PumpType
import info.nightscout.interfaces.queue.Callback
@@ -70,6 +72,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
@Inject lateinit var bleComm: BLEComm
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var pumpSync: PumpSync
+ @Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
@Inject lateinit var dateUtil: DateUtil
companion object {
@@ -245,18 +248,39 @@ class MedtrumService : DaggerService(), BLECommCallback {
return sendPacketAndGetResponse(SetPatchPacket(injector))
}
- fun setBolus(insulin: Double, t: EventOverviewBolusProgress.Treatment): Boolean {
+ fun setBolus(detailedBolusInfo: DetailedBolusInfo, t: EventOverviewBolusProgress.Treatment): Boolean {
if (!isConnected) return false
+ val insulin = detailedBolusInfo.insulin
val result = sendPacketAndGetResponse(SetBolusPacket(injector, insulin))
+ val bolusStart = System.currentTimeMillis()
+
medtrumPump.bolusDone = false
medtrumPump.bolusingTreatment = t
medtrumPump.bolusAmountToBeDelivered = insulin
medtrumPump.bolusStopped = false
medtrumPump.bolusStopForced = false
- medtrumPump.bolusProgressLastTimeStamp = dateUtil.now()
+ medtrumPump.bolusProgressLastTimeStamp = bolusStart
- val bolusStart = System.currentTimeMillis()
+ detailedBolusInfo.timestamp = bolusStart // Make sure the timestamp is set to the start of the bolus
+ detailedBolusInfoStorage.add(detailedBolusInfo) // will be picked up on reading history
+ // Sync the initial bolus
+ val newRecord = pumpSync.addBolusWithTempId(
+ timestamp = detailedBolusInfo.timestamp,
+ amount = detailedBolusInfo.insulin,
+ temporaryId = detailedBolusInfo.timestamp,
+ type = detailedBolusInfo.bolusType,
+ pumpType = medtrumPump.pumpType(),
+ pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
+ )
+ if (newRecord) {
+ aapsLogger.debug(
+ LTag.PUMPCOMM,
+ "set bolus: **NEW** EVENT BOLUS (tempId) ${dateUtil.dateAndTimeString(detailedBolusInfo.timestamp)} (${detailedBolusInfo.timestamp}) Bolus: ${detailedBolusInfo.insulin}U "
+ )
+ } else {
+ aapsLogger.error(LTag.PUMPCOMM, "Bolus with tempId ${detailedBolusInfo.timestamp} already exists")
+ }
val bolusingEvent = EventOverviewBolusProgress
while (medtrumPump.bolusStopped == false && result == true && medtrumPump.bolusDone == false) {
@@ -264,7 +288,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
if (System.currentTimeMillis() - medtrumPump.bolusProgressLastTimeStamp > T.secs(15).msecs()) {
medtrumPump.bolusStopped = true
medtrumPump.bolusStopForced = true
- aapsLogger.debug(LTag.PUMPCOMM, "Communication stopped")
+ aapsLogger.warn(LTag.PUMPCOMM, "Communication stopped")
bleComm.disconnect("Communication stopped")
} else {
bolusingEvent.t = medtrumPump.bolusingTreatment
From 3ffb78a7e85dfa111e864e3a61c1acd5d9fa44b7 Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Fri, 23 Jun 2023 11:42:45 +0200
Subject: [PATCH 050/116] Fix ANR, optimize write delay
---
.../info/nightscout/pump/medtrum/services/BLEComm.kt | 10 ++++++----
.../nightscout/pump/medtrum/services/MedtrumService.kt | 2 +-
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
index 8707aa1309..beba3622d0 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/BLEComm.kt
@@ -72,7 +72,7 @@ class BLEComm @Inject internal constructor(
companion object {
- private const val WRITE_DELAY_MILLIS: Long = 100
+ private const val WRITE_DELAY_MILLIS: Long = 10
private const val SERVICE_UUID = "669A9001-0008-968F-E311-6050405558B3"
private const val READ_UUID = "669a9120-0008-968f-e311-6050405558b3"
private const val WRITE_UUID = "669a9101-0008-968f-e311-6050405558b3"
@@ -455,11 +455,13 @@ class BLEComm @Inject internal constructor(
} else {
characteristic.value = data
characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
- aapsLogger.debug(LTag.PUMPBTCOMM, "writeCharacteristic:" + Arrays.toString(data))
- mBluetoothGatt?.writeCharacteristic(characteristic)
+ aapsLogger.debug(LTag.PUMPBTCOMM, "writeCharacteristic: ${Arrays.toString(data)}")
+ val success = mBluetoothGatt?.writeCharacteristic(characteristic)
+ if (success != true) {
+ mCallback?.onSendMessageError("Failed to write characteristic")
+ }
}
}, WRITE_DELAY_MILLIS)
- SystemClock.sleep(WRITE_DELAY_MILLIS)
}
private val uartWriteBTGattChar: BluetoothGattCharacteristic
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 60d6b5ba8f..9985c85e48 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -92,7 +92,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
private var currentState: State = IdleState()
private var mPacket: MedtrumPacket? = null
- private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
+ private val scope = CoroutineScope(Dispatchers.Default)
val isConnected: Boolean
get() = medtrumPump.connectionState == ConnectionState.CONNECTED
From 895cf54a17b7cec711d13e331b878e2b25756b2e Mon Sep 17 00:00:00 2001
From: jbr7rr <>
Date: Sun, 25 Jun 2023 10:21:47 +0200
Subject: [PATCH 051/116] Implemented proper activation and deactivation
screens
---
.../nightscout/interfaces/pump/Medtrum.kt | 1 +
.../nightscout/interfaces/queue/Command.kt | 1 +
.../interfaces/queue/CommandQueue.kt | 1 +
core/ui/src/main/res/values/strings.xml | 1 +
.../implementation/di/CommandQueueModule.kt | 2 +
.../queue/CommandQueueImplementation.kt | 14 ++
.../queue/commands/CommandClearAlarms.kt | 2 +-
.../queue/commands/CommandDeactivate.kt | 39 ++++
.../queue/CommandQueueImplementationTest.kt | 20 ++
.../nightscout/pump/medtrum/MedtrumPlugin.kt | 12 +-
.../nightscout/pump/medtrum/code/PatchStep.kt | 10 +-
.../medtrum/comm/packets/GetRecordPacket.kt | 4 +-
.../pump/medtrum/di/MedtrumModule.kt | 37 ++-
.../pump/medtrum/services/MedtrumService.kt | 20 +-
.../ui/MedtrumActivateCompleteFragment.kt | 53 +++++
.../medtrum/ui/MedtrumActivateFragment.kt | 24 +-
.../pump/medtrum/ui/MedtrumActivity.kt | 52 ++++-
.../medtrum/ui/MedtrumAttachPatchFragment.kt | 10 +-
.../ui/MedtrumDeactivatePatchFragment.kt | 15 +-
.../ui/MedtrumDeactivationCompleteFragment.kt | 37 +++
.../ui/MedtrumPreparePatchConnectFragment.kt | 51 +++++
.../medtrum/ui/MedtrumPreparePatchFragment.kt | 19 +-
.../ui/MedtrumPrimeCompleteFragment.kt | 50 +++++
.../pump/medtrum/ui/MedtrumPrimeFragment.kt | 11 +-
.../pump/medtrum/ui/MedtrumPrimingFragment.kt | 57 +++++
.../ui/MedtrumStartDeactivationFragment.kt | 16 +-
.../medtrum/ui/viewmodel/BaseViewModel.kt | 12 +-
.../medtrum/ui/viewmodel/MedtrumViewModel.kt | 211 ++++++++++--------
.../res/layout/fragment_medtrum_activate.xml | 23 +-
.../fragment_medtrum_activate_complete.xml | 80 +++++++
.../layout/fragment_medtrum_attach_patch.xml | 33 ++-
.../fragment_medtrum_deactivate_patch.xml | 24 +-
...fragment_medtrum_deactivation_complete.xml | 92 ++++++++
.../layout/fragment_medtrum_prepare_patch.xml | 53 ++++-
...fragment_medtrum_prepare_patch_connect.xml | 110 +++++++++
.../res/layout/fragment_medtrum_prime.xml | 41 +++-
.../fragment_medtrum_prime_complete.xml | 97 ++++++++
.../res/layout/fragment_medtrum_priming.xml | 108 +++++++++
.../fragment_medtrum_start_deactivation.xml | 36 ++-
pump/medtrum/src/main/res/values/strings.xml | 48 +++-
40 files changed, 1307 insertions(+), 220 deletions(-)
create mode 100644 implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandDeactivate.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateCompleteFragment.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivationCompleteFragment.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchConnectFragment.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeCompleteFragment.kt
create mode 100644 pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimingFragment.kt
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_activate_complete.xml
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_deactivation_complete.xml
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_prepare_patch_connect.xml
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_prime_complete.xml
create mode 100644 pump/medtrum/src/main/res/layout/fragment_medtrum_priming.xml
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
index 92ebebf2dc..1310693dc0 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/pump/Medtrum.kt
@@ -8,4 +8,5 @@ interface Medtrum {
fun loadEvents(): PumpEnactResult // events history to build treatments from
fun setUserOptions(): PumpEnactResult // set user settings
fun clearAlarms(): PumpEnactResult // clear alarms
+ fun deactivate(): PumpEnactResult // deactivate patch
}
\ No newline at end of file
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/queue/Command.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/queue/Command.kt
index fce81c02bf..96efac7dd7 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/queue/Command.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/queue/Command.kt
@@ -29,6 +29,7 @@ abstract class Command(
START_PUMP,
STOP_PUMP,
CLEAR_ALARMS, // so far only Medtrum specific
+ DEACTIVATE, // so far only Medtrum specific
INSIGHT_SET_TBR_OVER_ALARM, // insight only
CUSTOM_COMMAND
}
diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/queue/CommandQueue.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/queue/CommandQueue.kt
index cbc413d97d..26cadfd6dc 100644
--- a/core/interfaces/src/main/java/info/nightscout/interfaces/queue/CommandQueue.kt
+++ b/core/interfaces/src/main/java/info/nightscout/interfaces/queue/CommandQueue.kt
@@ -32,6 +32,7 @@ interface CommandQueue {
fun loadTDDs(callback: Callback?): Boolean
fun loadEvents(callback: Callback?): Boolean
fun clearAlarms(callback: Callback?): Boolean
+ fun deactivate(callback: Callback?): Boolean
fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean
fun isCustomCommandRunning(customCommandType: Class): Boolean
fun isCustomCommandInQueue(customCommandType: Class): Boolean
diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml
index 3d27666bf4..228f1cfa92 100644
--- a/core/ui/src/main/res/values/strings.xml
+++ b/core/ui/src/main/res/values/strings.xml
@@ -394,6 +394,7 @@
EXTENDED BOLUS %1$.2f U %2$d min
LOAD EVENTS
CLEAR_ALARMS
+ DEACTIVATE
LOAD HISTORY %1$d
LOAD TDDs
SET PROFILE
diff --git a/implementation/src/main/java/info/nightscout/implementation/di/CommandQueueModule.kt b/implementation/src/main/java/info/nightscout/implementation/di/CommandQueueModule.kt
index 0e9a04ba45..ecdb7ae52f 100644
--- a/implementation/src/main/java/info/nightscout/implementation/di/CommandQueueModule.kt
+++ b/implementation/src/main/java/info/nightscout/implementation/di/CommandQueueModule.kt
@@ -16,6 +16,7 @@ import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
import info.nightscout.implementation.queue.commands.CommandClearAlarms
import info.nightscout.implementation.queue.commands.CommandCustomCommand
+import info.nightscout.implementation.queue.commands.CommandDeactivate
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
import info.nightscout.implementation.queue.commands.CommandLoadEvents
@@ -34,6 +35,7 @@ abstract class CommandQueueModule {
@ContributesAndroidInjector abstract fun commandInsightSetTBROverNotificationInjector(): CommandInsightSetTBROverNotification
@ContributesAndroidInjector abstract fun commandLoadEventsInjector(): CommandLoadEvents
@ContributesAndroidInjector abstract fun commandClearAlarmsInjector(): CommandClearAlarms
+ @ContributesAndroidInjector abstract fun commandDeactivateInjector(): CommandDeactivate
@ContributesAndroidInjector abstract fun commandLoadHistoryInjector(): CommandLoadHistory
@ContributesAndroidInjector abstract fun commandLoadTDDsInjector(): CommandLoadTDDs
@ContributesAndroidInjector abstract fun commandReadStatusInjector(): CommandReadStatus
diff --git a/implementation/src/main/java/info/nightscout/implementation/queue/CommandQueueImplementation.kt b/implementation/src/main/java/info/nightscout/implementation/queue/CommandQueueImplementation.kt
index 18cbf76b38..f36d42836a 100644
--- a/implementation/src/main/java/info/nightscout/implementation/queue/CommandQueueImplementation.kt
+++ b/implementation/src/main/java/info/nightscout/implementation/queue/CommandQueueImplementation.kt
@@ -24,6 +24,7 @@ import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
import info.nightscout.implementation.queue.commands.CommandClearAlarms
import info.nightscout.implementation.queue.commands.CommandCustomCommand
+import info.nightscout.implementation.queue.commands.CommandDeactivate
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
import info.nightscout.implementation.queue.commands.CommandLoadEvents
@@ -550,6 +551,19 @@ class CommandQueueImplementation @Inject constructor(
return true
}
+ override fun deactivate(callback: Callback?): Boolean {
+ if (isRunning(CommandType.DEACTIVATE)) {
+ callback?.result(executingNowError())?.run()
+ return false
+ }
+ // remove all unfinished
+ removeAll(CommandType.DEACTIVATE)
+ // add new command to queue
+ add(CommandDeactivate(injector, callback))
+ notifyAboutNewCommand()
+ return true
+ }
+
override fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean {
if (isCustomCommandInQueue(customCommand.javaClass)) {
callback?.result(executingNowError())?.run()
diff --git a/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandClearAlarms.kt b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandClearAlarms.kt
index cbfb184d61..00e5bb1ff0 100644
--- a/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandClearAlarms.kt
+++ b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandClearAlarms.kt
@@ -31,7 +31,7 @@ class CommandClearAlarms(
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.clear_alarms)
- override fun log(): String = "CLEAR ALAMRS"
+ override fun log(): String = "CLEAR ALARMS"
override fun cancel() {
aapsLogger.debug(LTag.PUMPQUEUE, "Result cancel")
callback?.result(PumpEnactResult(injector).success(false).comment(info.nightscout.core.ui.R.string.connectiontimedout))?.run()
diff --git a/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandDeactivate.kt b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandDeactivate.kt
new file mode 100644
index 0000000000..eef55c1ecc
--- /dev/null
+++ b/implementation/src/main/java/info/nightscout/implementation/queue/commands/CommandDeactivate.kt
@@ -0,0 +1,39 @@
+package info.nightscout.implementation.queue.commands
+
+import dagger.android.HasAndroidInjector
+import info.nightscout.interfaces.plugin.ActivePlugin
+import info.nightscout.interfaces.pump.Dana
+import info.nightscout.interfaces.pump.Diaconn
+import info.nightscout.interfaces.pump.Medtrum
+import info.nightscout.interfaces.pump.PumpEnactResult
+import info.nightscout.interfaces.queue.Callback
+import info.nightscout.interfaces.queue.Command
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class CommandDeactivate(
+ injector: HasAndroidInjector,
+ callback: Callback?
+) : Command(injector, CommandType.DEACTIVATE, callback) {
+
+ @Inject lateinit var activePlugin: ActivePlugin
+
+ override fun execute() {
+ val pump = activePlugin.activePump
+
+ if (pump is Medtrum) {
+ val medtrumPump = pump as Medtrum
+ val r = medtrumPump.deactivate()
+ aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
+ callback?.result(r)?.run()
+ }
+ }
+
+ override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.deactivate)
+
+ override fun log(): String = "DEACTIVATE"
+ override fun cancel() {
+ aapsLogger.debug(LTag.PUMPQUEUE, "Result cancel")
+ callback?.result(PumpEnactResult(injector).success(false).comment(info.nightscout.core.ui.R.string.connectiontimedout))?.run()
+ }
+}
diff --git a/implementation/src/test/java/info/nightscout/implementation/queue/CommandQueueImplementationTest.kt b/implementation/src/test/java/info/nightscout/implementation/queue/CommandQueueImplementationTest.kt
index 38165f5c90..9c12a6e421 100644
--- a/implementation/src/test/java/info/nightscout/implementation/queue/CommandQueueImplementationTest.kt
+++ b/implementation/src/test/java/info/nightscout/implementation/queue/CommandQueueImplementationTest.kt
@@ -242,6 +242,10 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
// add clearAlarms
commandQueue.clearAlarms(null)
Assertions.assertEquals(5, commandQueue.size())
+
+ // add deactivate
+ commandQueue.deactivate(null)
+ Assertions.assertEquals(6, commandQueue.size())
commandQueue.clear()
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
@@ -375,6 +379,22 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
Assertions.assertEquals(1, commandQueue.size())
}
+ @Test
+ fun isDeactivateCommandInQueue() {
+ // given
+ Assertions.assertEquals(0, commandQueue.size())
+
+ // when
+ commandQueue.deactivate(null)
+
+ // then
+ Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.DEACTIVATE))
+ Assertions.assertEquals(1, commandQueue.size())
+ // next should be ignored
+ commandQueue.deactivate(null)
+ Assertions.assertEquals(1, commandQueue.size())
+ }
+
@Test
fun isLoadTDDsCommandInQueue() {
// given
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
index 1a466b2f43..c01623be66 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/MedtrumPlugin.kt
@@ -82,7 +82,7 @@ import kotlin.math.round
PluginDescription()
.mainType(PluginType.PUMP)
.fragmentClass(MedtrumOverviewFragment::class.java.name)
- .pluginIcon(info.nightscout.core.ui.R.drawable.ic_eopatch2_128) // TODO
+ .pluginIcon(info.nightscout.core.ui.R.drawable.ic_generic_icon) // TODO
.pluginName(R.string.medtrum)
.shortName(R.string.medtrum_pump_shortname)
.preferencesId(R.xml.pref_medtrum_pump)
@@ -442,4 +442,14 @@ import kotlin.math.round
val connectionOK = medtrumService?.clearAlarms() ?: false
return PumpEnactResult(injector).success(connectionOK)
}
+
+ override fun deactivate(): PumpEnactResult {
+ // if (!isInitialized()) {
+ // val result = PumpEnactResult(injector).success(false)
+ // result.comment = "pump not initialized"
+ // return result
+ // }
+ val connectionOK = medtrumService?.deactivatePatch() ?: false
+ return PumpEnactResult(injector).success(connectionOK)
+ }
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
index c3e7bc9ab5..bba4cdfecb 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/code/PatchStep.kt
@@ -3,13 +3,17 @@ package info.nightscout.pump.medtrum.code
enum class PatchStep {
START_DEACTIVATION,
DEACTIVATE,
+ FORCE_DEACTIVATION,
DEACTIVATION_COMPLETE,
PREPARE_PATCH,
+ PREPARE_PATCH_CONNECT,
PRIME,
+ PRIMING,
+ PRIME_COMPLETE,
ATTACH_PATCH,
ACTIVATE,
+ ACTIVATE_COMPLETE,
+ ERROR,
CANCEL,
- COMPLETE,
- BACK_TO_HOME,
- FINISH;
+ COMPLETE;
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
index 99a46174bd..3d4ca93cad 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/comm/packets/GetRecordPacket.kt
@@ -112,7 +112,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(bolusStartTime, bolusNormalDelivered)
var newRecord = false
if (detailedBolusInfo != null) {
- val success = pumpSync.syncBolusWithTempId(
+ val syncOk = pumpSync.syncBolusWithTempId(
timestamp = bolusStartTime,
amount = bolusNormalDelivered,
temporaryId = detailedBolusInfo.timestamp,
@@ -121,7 +121,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
- if (success == false) {
+ if (syncOk == false) {
aapsLogger.warn(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD: Failed to sync bolus with tempId: ${detailedBolusInfo.timestamp}")
// detailedInfo can be from another similar record. Reinsert
detailedBolusInfoStorage.add(detailedBolusInfo)
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
index 429cf3f319..4dd4612536 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/di/MedtrumModule.kt
@@ -7,13 +7,18 @@ import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoMap
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumActivateFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumDeactivatePatchFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumStartDeactivationFragment
import info.nightscout.pump.medtrum.services.MedtrumService
+import info.nightscout.pump.medtrum.ui.MedtrumActivateCompleteFragment
+import info.nightscout.pump.medtrum.ui.MedtrumActivateFragment
+import info.nightscout.pump.medtrum.ui.MedtrumAttachPatchFragment
+import info.nightscout.pump.medtrum.ui.MedtrumDeactivatePatchFragment
+import info.nightscout.pump.medtrum.ui.MedtrumDeactivationCompleteFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPreparePatchConnectFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPreparePatchFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPrimeCompleteFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPrimeFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPrimingFragment
+import info.nightscout.pump.medtrum.ui.MedtrumStartDeactivationFragment
import info.nightscout.pump.medtrum.ui.MedtrumActivity
import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumOverviewViewModel
@@ -60,14 +65,30 @@ abstract class MedtrumModule {
@ContributesAndroidInjector
internal abstract fun contributesDeactivatePatchFragment(): MedtrumDeactivatePatchFragment
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesDeactivationCompleteFragment(): MedtrumDeactivationCompleteFragment
+
@FragmentScope
@ContributesAndroidInjector
internal abstract fun contributesPreparePatchFragment(): MedtrumPreparePatchFragment
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesPreparePatchConnectFragment(): MedtrumPreparePatchConnectFragment
+
@FragmentScope
@ContributesAndroidInjector
internal abstract fun contributesPrimeFragment(): MedtrumPrimeFragment
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesPrimeCompleteFragment(): MedtrumPrimeCompleteFragment
+
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesPrimingFragment(): MedtrumPrimingFragment
+
@FragmentScope
@ContributesAndroidInjector
internal abstract fun contributesAttachPatchFragment(): MedtrumAttachPatchFragment
@@ -76,6 +97,10 @@ abstract class MedtrumModule {
@ContributesAndroidInjector
internal abstract fun contributesActivateFragment(): MedtrumActivateFragment
+ @FragmentScope
+ @ContributesAndroidInjector
+ internal abstract fun contributesActivateCompleteFragment(): MedtrumActivateCompleteFragment
+
// ACTIVITIES
@ContributesAndroidInjector
abstract fun contributesMedtrumActivity(): MedtrumActivity
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
index 9985c85e48..26bbc22f7e 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/services/MedtrumService.kt
@@ -414,12 +414,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Map the pump state to a notification
when (state) {
MedtrumPumpState.NONE,
- MedtrumPumpState.IDLE,
- MedtrumPumpState.FILLED,
- MedtrumPumpState.PRIMING,
- MedtrumPumpState.PRIMED,
- MedtrumPumpState.EJECTING,
- MedtrumPumpState.EJECTED,
MedtrumPumpState.STOPPED -> {
rxBus.send(EventDismissNotification(Notification.PUMP_ERROR))
rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
@@ -432,6 +426,18 @@ class MedtrumService : DaggerService(), BLECommCallback {
medtrumPump.clearAlarmState()
}
+ MedtrumPumpState.IDLE,
+ MedtrumPumpState.FILLED,
+ MedtrumPumpState.PRIMING,
+ MedtrumPumpState.PRIMED,
+ MedtrumPumpState.EJECTING,
+ MedtrumPumpState.EJECTED -> {
+ rxBus.send(EventDismissNotification(Notification.PUMP_ERROR))
+ rxBus.send(EventDismissNotification(Notification.PUMP_SUSPENDED))
+ medtrumPump.setFakeTBRIfNeeded()
+ medtrumPump.clearAlarmState()
+ }
+
MedtrumPumpState.ACTIVE,
MedtrumPumpState.ACTIVE_ALT -> {
rxBus.send(EventDismissNotification(Notification.PATCH_NOT_ACTIVE))
@@ -599,7 +605,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
}
fun onSendMessageError(reason: String) {
- aapsLogger.debug(LTag.PUMPCOMM, "onSendMessageError: " + this.toString() + "reason: $reason")
+ aapsLogger.warn(LTag.PUMPCOMM, "onSendMessageError: " + this.toString() + "reason: $reason")
responseHandled = true
responseSuccess = false
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateCompleteFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateCompleteFragment.kt
new file mode 100644
index 0000000000..ef9a94ca16
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateCompleteFragment.kt
@@ -0,0 +1,53 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumActivateBinding
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumActivateCompleteBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumActivateCompleteFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumActivateCompleteFragment = MedtrumActivateCompleteFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_activate_complete
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.INITIAL,
+ MedtrumViewModel.SetupStep.PRIMED -> Unit // Nothing to do here, previous state
+ MedtrumViewModel.SetupStep.ACTIVATED -> btnPositive.visibility = View.VISIBLE
+
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error Activating") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+
+ else -> {
+ ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
+ aapsLogger.error(LTag.PUMP, "Unexpected state: $it")
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateFragment.kt
index ab788b9d4b..2af09f86a5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivateFragment.kt
@@ -1,4 +1,4 @@
-package info.nightscout.androidaps.plugins.pump.eopatch.ui
+package info.nightscout.pump.medtrum.ui
import android.os.Bundle
import android.view.View
@@ -11,11 +11,13 @@ import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.interfaces.ResourceHelper
import javax.inject.Inject
class MedtrumActivateFragment : MedtrumBaseFragment() {
@Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var rh: ResourceHelper
companion object {
@@ -31,16 +33,20 @@ class MedtrumActivateFragment : MedtrumBaseFragment Unit // Nothing to do here, previous state
- MedtrumViewModel.SetupStep.ACTIVATED -> btnPositive.visibility = View.VISIBLE
- MedtrumViewModel.SetupStep.ERROR -> {
- ToastUtils.errorToast(requireContext(), "Error Activating") // TODO: String resource and show error message
- moveStep(PatchStep.CANCEL)
+ MedtrumViewModel.SetupStep.INITIAL,
+ MedtrumViewModel.SetupStep.PRIMED -> Unit // Nothing to do here, previous state
+ MedtrumViewModel.SetupStep.ACTIVATED -> moveStep(PatchStep.ACTIVATE_COMPLETE)
+
+ MedtrumViewModel.SetupStep.ERROR -> {
+ moveStep(PatchStep.ERROR)
+ updateSetupStep(MedtrumViewModel.SetupStep.PRIMED) // Reset setup step
+ binding.textActivatingPump.text = rh.gs(R.string.activating_error)
+ binding.btnPositive.visibility = View.VISIBLE
}
- else -> {
- ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
- moveStep(PatchStep.CANCEL)
+ else -> {
+ ToastUtils.errorToast(requireContext(), "Unexpected state: $it")
+ aapsLogger.error(LTag.PUMP, "Unexpected state: $it")
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
index 77656cefb5..2534cb253b 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumActivity.kt
@@ -3,21 +3,29 @@ package info.nightscout.pump.medtrum.ui
import android.app.Dialog
import android.content.Context
import android.content.Intent
+import android.content.pm.ActivityInfo
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.os.Bundle
import android.view.MotionEvent
+import android.view.WindowManager
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.ViewModelProvider
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumActivateFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumAttachPatchFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumDeactivatePatchFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPreparePatchFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumPrimeFragment
-import info.nightscout.androidaps.plugins.pump.eopatch.ui.MedtrumStartDeactivationFragment
+import info.nightscout.pump.medtrum.ui.MedtrumActivateCompleteFragment
+import info.nightscout.pump.medtrum.ui.MedtrumActivateFragment
+import info.nightscout.pump.medtrum.ui.MedtrumAttachPatchFragment
+import info.nightscout.pump.medtrum.ui.MedtrumDeactivatePatchFragment
+import info.nightscout.pump.medtrum.ui.MedtrumDeactivationCompleteFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPreparePatchConnectFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPreparePatchFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPrimeCompleteFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPrimeFragment
+import info.nightscout.pump.medtrum.ui.MedtrumPrimingFragment
+import info.nightscout.pump.medtrum.ui.MedtrumStartDeactivationFragment
import info.nightscout.core.utils.extensions.safeGetSerializableExtra
import info.nightscout.pump.medtrum.R
import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
import info.nightscout.pump.medtrum.databinding.ActivityMedtrumBinding
import info.nightscout.pump.medtrum.extension.replaceFragmentInActivity
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
@@ -36,6 +44,8 @@ class MedtrumActivity : MedtrumBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
binding.apply {
viewModel = ViewModelProvider(this@MedtrumActivity, viewModelFactory).get(MedtrumViewModel::class.java)
@@ -45,15 +55,33 @@ class MedtrumActivity : MedtrumBaseActivity() {
patchStep.observe(this@MedtrumActivity) {
when (it) {
PatchStep.PREPARE_PATCH -> setupViewFragment(MedtrumPreparePatchFragment.newInstance())
+ PatchStep.PREPARE_PATCH_CONNECT -> setupViewFragment(MedtrumPreparePatchConnectFragment.newInstance())
PatchStep.PRIME -> setupViewFragment(MedtrumPrimeFragment.newInstance())
+ PatchStep.PRIMING -> setupViewFragment(MedtrumPrimingFragment.newInstance())
+ PatchStep.PRIME_COMPLETE -> setupViewFragment(MedtrumPrimeCompleteFragment.newInstance())
PatchStep.ATTACH_PATCH -> setupViewFragment(MedtrumAttachPatchFragment.newInstance())
PatchStep.ACTIVATE -> setupViewFragment(MedtrumActivateFragment.newInstance())
- PatchStep.COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
- PatchStep.CANCEL -> this@MedtrumActivity.finish()
+ PatchStep.ACTIVATE_COMPLETE -> setupViewFragment(MedtrumActivateCompleteFragment.newInstance())
+ PatchStep.COMPLETE -> this@MedtrumActivity.finish()
+ PatchStep.ERROR -> Unit // Do nothing, let activity handle this
+
+ PatchStep.CANCEL -> {
+ if (setupStep.value !in listOf(MedtrumViewModel.SetupStep.ACTIVATED, MedtrumViewModel.SetupStep.START_DEACTIVATION, MedtrumViewModel.SetupStep.STOPPED)) {
+ resetPumpState()
+ }
+ this@MedtrumActivity.finish()
+ }
+
PatchStep.START_DEACTIVATION -> setupViewFragment(MedtrumStartDeactivationFragment.newInstance())
PatchStep.DEACTIVATE -> setupViewFragment(MedtrumDeactivatePatchFragment.newInstance())
- PatchStep.DEACTIVATION_COMPLETE -> this@MedtrumActivity.finish() // TODO proper finish
- else -> Unit
+
+ PatchStep.FORCE_DEACTIVATION -> {
+ medtrumPump.pumpState = MedtrumPumpState.STOPPED
+ moveStep(PatchStep.DEACTIVATION_COMPLETE)
+ }
+
+ PatchStep.DEACTIVATION_COMPLETE -> setupViewFragment(MedtrumDeactivationCompleteFragment.newInstance())
+ null -> Unit
}
}
}
@@ -69,7 +97,9 @@ class MedtrumActivity : MedtrumBaseActivity() {
binding.viewModel?.apply {
intent?.run {
val step = intent.safeGetSerializableExtra(EXTRA_START_PATCH_STEP, PatchStep::class.java)
- initializePatchStep(step)
+ if (step != null) {
+ initializePatchStep(step)
+ }
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumAttachPatchFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumAttachPatchFragment.kt
index b8741413b7..97baead2b1 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumAttachPatchFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumAttachPatchFragment.kt
@@ -1,4 +1,4 @@
-package info.nightscout.androidaps.plugins.pump.eopatch.ui
+package info.nightscout.pump.medtrum.ui
import android.os.Bundle
import android.view.View
@@ -32,14 +32,16 @@ class MedtrumAttachPatchFragment : MedtrumBaseFragment Unit // Nothing to do here, previous state
- MedtrumViewModel.SetupStep.ERROR -> {
+ MedtrumViewModel.SetupStep.ERROR -> {
ToastUtils.errorToast(requireContext(), "Error attach patch") // TODO: String resource and show error message
moveStep(PatchStep.CANCEL)
}
- else -> {
+
+ else -> {
ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
- moveStep(PatchStep.CANCEL)
+ aapsLogger.error(LTag.PUMP, "Unexpected state: $it")
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivatePatchFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivatePatchFragment.kt
index 0791f8cb79..b996fa778e 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivatePatchFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivatePatchFragment.kt
@@ -1,4 +1,4 @@
-package info.nightscout.androidaps.plugins.pump.eopatch.ui
+package info.nightscout.pump.medtrum.ui
import android.os.Bundle
import android.view.View
@@ -11,11 +11,13 @@ import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.interfaces.ResourceHelper
import javax.inject.Inject
class MedtrumDeactivatePatchFragment : MedtrumBaseFragment() {
@Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var rh: ResourceHelper
companion object {
@@ -32,11 +34,16 @@ class MedtrumDeactivatePatchFragment : MedtrumBaseFragment btnPositive.visibility = View.VISIBLE
+ MedtrumViewModel.SetupStep.STOPPED -> {
+ moveStep(PatchStep.DEACTIVATION_COMPLETE)
+ }
MedtrumViewModel.SetupStep.ERROR -> {
- ToastUtils.errorToast(requireContext(), "Error deactivate") // TODO: String resource and show error message
- moveStep(PatchStep.CANCEL)
+ moveStep(PatchStep.ERROR)
+ updateSetupStep(MedtrumViewModel.SetupStep.START_DEACTIVATION) // Reset setup step
+ binding.textDeactivatingPump.text = rh.gs(R.string.deactivating_error)
+ binding.btnNegative.visibility = View.VISIBLE
+ binding.btnPositive.visibility = View.VISIBLE
}
else -> Unit // Nothing to do here
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivationCompleteFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivationCompleteFragment.kt
new file mode 100644
index 0000000000..b433a0fad8
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumDeactivationCompleteFragment.kt
@@ -0,0 +1,37 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumDeactivationCompleteBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumDeactivationCompleteFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumDeactivationCompleteFragment = MedtrumDeactivationCompleteFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_deactivation_complete
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ aapsLogger.debug(LTag.PUMP, "MedtrumStartDeactivationFragment onViewCreated")
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ // Nothing to do here (yet)
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchConnectFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchConnectFragment.kt
new file mode 100644
index 0000000000..0664d27ead
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchConnectFragment.kt
@@ -0,0 +1,51 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPreparePatchConnectBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumPreparePatchConnectFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumPreparePatchConnectFragment = MedtrumPreparePatchConnectFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_prepare_patch_connect
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ aapsLogger.debug(LTag.PUMP, "MedtrumPreparePatchFragment onViewCreated")
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.INITIAL -> btnPositive.visibility = View.GONE
+ // TODO: Confirmation dialog
+ MedtrumViewModel.SetupStep.FILLED -> btnPositive.visibility = View.VISIBLE
+
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error preparing patch") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+
+ else -> Unit
+ }
+ }
+ preparePatchConnect()
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
index d044e82073..7c0c319025 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPreparePatchFragment.kt
@@ -1,4 +1,4 @@
-package info.nightscout.androidaps.plugins.pump.eopatch.ui
+package info.nightscout.pump.medtrum.ui
import android.os.Bundle
import android.view.View
@@ -30,23 +30,6 @@ class MedtrumPreparePatchFragment : MedtrumBaseFragment btnPositive.visibility = View.GONE
- // TODO: Confirmation dialog
- MedtrumViewModel.SetupStep.FILLED -> btnPositive.visibility = View.VISIBLE
-
- MedtrumViewModel.SetupStep.ERROR -> {
- ToastUtils.errorToast(requireContext(), "Error preparing patch") // TODO: String resource and show error message
- moveStep(PatchStep.CANCEL)
- }
-
- else -> {
- ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
- moveStep(PatchStep.CANCEL)
- }
- }
- }
preparePatch()
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeCompleteFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeCompleteFragment.kt
new file mode 100644
index 0000000000..38be727974
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeCompleteFragment.kt
@@ -0,0 +1,50 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPrimeCompleteBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import javax.inject.Inject
+
+class MedtrumPrimeCompleteFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+
+ companion object {
+
+ fun newInstance(): MedtrumPrimeCompleteFragment = MedtrumPrimeCompleteFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_prime_complete
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.INITIAL,
+ MedtrumViewModel.SetupStep.PRIMED -> Unit // Nothing to do here, previous state
+ MedtrumViewModel.SetupStep.ERROR -> {
+ ToastUtils.errorToast(requireContext(), "Error priming") // TODO: String resource and show error message
+ moveStep(PatchStep.CANCEL)
+ }
+
+ else -> {
+ ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
+ aapsLogger.error(LTag.PUMP, "Unexpected state: $it")
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
index d0903226b0..49839bee3f 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimeFragment.kt
@@ -1,4 +1,4 @@
-package info.nightscout.androidaps.plugins.pump.eopatch.ui
+package info.nightscout.pump.medtrum.ui
import android.os.Bundle
import android.view.View
@@ -31,20 +31,19 @@ class MedtrumPrimeFragment : MedtrumBaseFragment()
viewModel?.apply {
setupStep.observe(viewLifecycleOwner) {
when (it) {
+ MedtrumViewModel.SetupStep.INITIAL,
MedtrumViewModel.SetupStep.FILLED -> Unit // Nothing to do here, previous state
- MedtrumViewModel.SetupStep.PRIMED -> btnPositive.visibility = View.VISIBLE
- MedtrumViewModel.SetupStep.ERROR -> {
+ MedtrumViewModel.SetupStep.ERROR -> {
ToastUtils.errorToast(requireContext(), "Error priming") // TODO: String resource and show error message
moveStep(PatchStep.CANCEL)
}
- else -> {
+ else -> {
ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
- moveStep(PatchStep.CANCEL)
+ aapsLogger.error(LTag.PUMP, "Unexpected state: $it")
}
}
}
- startPrime()
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimingFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimingFragment.kt
new file mode 100644
index 0000000000..6e2defca85
--- /dev/null
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumPrimingFragment.kt
@@ -0,0 +1,57 @@
+package info.nightscout.pump.medtrum.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.ViewModelProvider
+import info.nightscout.core.ui.toast.ToastUtils
+import info.nightscout.pump.medtrum.R
+import info.nightscout.pump.medtrum.code.PatchStep
+import info.nightscout.pump.medtrum.databinding.FragmentMedtrumPrimingBinding
+import info.nightscout.pump.medtrum.ui.MedtrumBaseFragment
+import info.nightscout.pump.medtrum.ui.viewmodel.MedtrumViewModel
+import info.nightscout.rx.logging.AAPSLogger
+import info.nightscout.rx.logging.LTag
+import info.nightscout.shared.interfaces.ResourceHelper
+import javax.inject.Inject
+
+class MedtrumPrimingFragment : MedtrumBaseFragment() {
+
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var rh: ResourceHelper
+
+ companion object {
+
+ fun newInstance(): MedtrumPrimingFragment = MedtrumPrimingFragment()
+ }
+
+ override fun getLayoutId(): Int = R.layout.fragment_medtrum_priming
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.apply {
+ viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MedtrumViewModel::class.java)
+ viewModel?.apply {
+ setupStep.observe(viewLifecycleOwner) {
+ when (it) {
+ MedtrumViewModel.SetupStep.INITIAL,
+ MedtrumViewModel.SetupStep.FILLED -> Unit // Nothing to do here, previous state
+ MedtrumViewModel.SetupStep.PRIMED -> moveStep(PatchStep.PRIME_COMPLETE)
+
+ MedtrumViewModel.SetupStep.ERROR -> {
+ moveStep(PatchStep.ERROR)
+ updateSetupStep(MedtrumViewModel.SetupStep.FILLED) // Reset setup step
+ binding.textWaitForPriming.text = rh.gs(R.string.priming_error)
+ binding.btnPositive.visibility = View.VISIBLE
+ }
+
+ else -> {
+ ToastUtils.errorToast(requireContext(), "Unexpected state: $it") // TODO: String resource and show error message
+ aapsLogger.error(LTag.PUMP, "Unexpected state: $it")
+ }
+ }
+ }
+ startPrime()
+ }
+ }
+ }
+}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumStartDeactivationFragment.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumStartDeactivationFragment.kt
index 7e9814c667..974ed08ec5 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumStartDeactivationFragment.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/MedtrumStartDeactivationFragment.kt
@@ -1,4 +1,4 @@
-package info.nightscout.androidaps.plugins.pump.eopatch.ui
+package info.nightscout.pump.medtrum.ui
import android.os.Bundle
import android.view.View
@@ -30,19 +30,7 @@ class MedtrumStartDeactivationFragment : MedtrumBaseFragment btnPositive.visibility = View.VISIBLE
-
- MedtrumViewModel.SetupStep.ERROR -> {
- ToastUtils.errorToast(requireContext(), "Error deactivate") // TODO: String resource and show error message
- moveStep(PatchStep.CANCEL)
- }
-
- else -> Unit // Nothing to do here
- }
- }
- startDeactivation()
+ updateSetupStep(MedtrumViewModel.SetupStep.START_DEACTIVATION)
}
}
}
diff --git a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
index a4b1b52831..0b69688829 100644
--- a/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
+++ b/pump/medtrum/src/main/java/info/nightscout/pump/medtrum/ui/viewmodel/BaseViewModel.kt
@@ -29,14 +29,4 @@ abstract class BaseViewModel