commit
da77dec5c9
174 changed files with 13649 additions and 16 deletions
|
@ -159,6 +159,10 @@ android {
|
|||
}
|
||||
|
||||
useLibrary "org.apache.http.legacy"
|
||||
|
||||
dataBinding { //Deleting it causes a binding error
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
@ -185,6 +189,7 @@ dependencies {
|
|||
implementation project(':pump:danars')
|
||||
implementation project(':pump:danar')
|
||||
implementation project(':pump:diaconn')
|
||||
implementation project(':pump:eopatch')
|
||||
implementation project(':insight')
|
||||
implementation project(':pump:medtronic')
|
||||
implementation project(':pump:pump-common')
|
||||
|
|
|
@ -38,6 +38,7 @@ import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
|||
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatusLinePlugin
|
||||
import info.nightscout.plugins.insulin.InsulinOrefFreePeakPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.EopatchPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||
|
@ -99,6 +100,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
@Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
|
||||
@Inject lateinit var wearPlugin: WearPlugin
|
||||
@Inject lateinit var maintenancePlugin: MaintenancePlugin
|
||||
@Inject lateinit var eopatchPumpPlugin: EopatchPumpPlugin
|
||||
|
||||
@Inject lateinit var passwordCheck: PasswordCheck
|
||||
@Inject lateinit var nsSettingStatus: NSSettingsStatus
|
||||
|
@ -187,6 +189,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
addPreferencesFromResourceIfEnabled(comboPlugin, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResourceIfEnabled(diaconnG8Plugin, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResourceIfEnabled(eopatchPumpPlugin, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
|
||||
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
|
||||
|
|
|
@ -19,6 +19,7 @@ import info.nightscout.androidaps.insight.di.InsightModule
|
|||
import info.nightscout.androidaps.plugin.general.openhumans.di.OpenHumansModule
|
||||
import info.nightscout.androidaps.plugins.pump.common.di.PumpCommonModule
|
||||
import info.nightscout.androidaps.plugins.pump.common.di.RileyLinkModule
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.dagger.EopatchModule
|
||||
import info.nightscout.androidaps.plugins.pump.medtronic.di.MedtronicModule
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.di.OmnipodDashModule
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.di.OmnipodErosModule
|
||||
|
@ -69,6 +70,7 @@ import javax.inject.Singleton
|
|||
WorkersModule::class,
|
||||
DiaconnG8Module::class,
|
||||
OpenHumansModule::class,
|
||||
EopatchModule::class,
|
||||
SharedModule::class,
|
||||
UiModule::class,
|
||||
InsulinModule::class
|
||||
|
|
|
@ -44,6 +44,7 @@ import info.nightscout.plugins.insulin.InsulinOrefUltraRapidActingPlugin
|
|||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.EopatchPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
|
||||
|
@ -182,9 +183,15 @@ abstract class PluginsModule {
|
|||
@Binds
|
||||
@PumpDriver
|
||||
@IntoMap
|
||||
@IntKey(160)
|
||||
@IntKey(155)
|
||||
abstract fun bindDiaconnG8Plugin(plugin: DiaconnG8Plugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@PumpDriver
|
||||
@IntoMap
|
||||
@IntKey(156)
|
||||
abstract fun bindEopatchPumpPlugin(plugin: EopatchPumpPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@AllConfigs
|
||||
@IntoMap
|
||||
|
|
|
@ -16,6 +16,7 @@ import info.nightscout.androidaps.utils.DateUtil
|
|||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.WarnColors
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.AppConstant
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
@ -34,7 +35,15 @@ class StatusLightHandler @Inject constructor(
|
|||
/**
|
||||
* applies the extended statusLight subview on the overview fragment
|
||||
*/
|
||||
fun updateStatusLights(careportal_cannula_age: TextView?, careportal_insulin_age: TextView?, careportal_reservoir_level: TextView?, careportal_sensor_age: TextView?, careportal_sensor_battery_level: TextView?, careportal_pb_age: TextView?, careportal_battery_level: TextView?) {
|
||||
fun updateStatusLights(
|
||||
careportal_cannula_age: TextView?,
|
||||
careportal_insulin_age: TextView?,
|
||||
careportal_reservoir_level: TextView?,
|
||||
careportal_sensor_age: TextView?,
|
||||
careportal_sensor_battery_level: TextView?,
|
||||
careportal_pb_age: TextView?,
|
||||
careportal_battery_level: TextView?
|
||||
) {
|
||||
val pump = activePlugin.activePump
|
||||
val bgSource = activePlugin.activeBgSource
|
||||
handleAge(careportal_cannula_age, TherapyEvent.Type.CANNULA_CHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0)
|
||||
|
@ -46,7 +55,11 @@ class StatusLightHandler @Inject constructor(
|
|||
|
||||
val insulinUnit = rh.gs(R.string.insulin_unit_shortname)
|
||||
if (pump.model() == PumpType.OMNIPOD_EROS || pump.model() == PumpType.OMNIPOD_DASH) {
|
||||
handleOmnipodReservoirLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, insulinUnit)
|
||||
handlePatchReservoirLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, insulinUnit,
|
||||
OmnipodConstants.MAX_RESERVOIR_READING)
|
||||
} else if (pump.model() == PumpType.EOFLOW_EOPATCH2) {
|
||||
handlePatchReservoirLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, insulinUnit,
|
||||
AppConstant.MAX_RESERVOIR_READING)
|
||||
} else {
|
||||
handleLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, insulinUnit)
|
||||
}
|
||||
|
@ -95,14 +108,16 @@ class StatusLightHandler @Inject constructor(
|
|||
|
||||
// Omnipod only reports reservoir level when it's 50 units or less, so we display "50+U" for any value > 50
|
||||
@Suppress("SameParameterValue")
|
||||
private fun handleOmnipodReservoirLevel(view: TextView?, criticalSetting: Int, criticalDefaultValue: Double, warnSetting: Int, warnDefaultValue: Double, level: Double, units: String) {
|
||||
if (level >= OmnipodConstants.MAX_RESERVOIR_READING) {
|
||||
private fun handlePatchReservoirLevel(
|
||||
view: TextView?, criticalSetting: Int, criticalDefaultValue: Double, warnSetting: Int,
|
||||
warnDefaultValue: Double, level: Double, units: String, maxReading: Double
|
||||
) {
|
||||
if (level >= maxReading) {
|
||||
@Suppress("SetTextI18n")
|
||||
view?.text = " 50+$units"
|
||||
view?.text = " ${maxReading.toInt()}+$units"
|
||||
view?.setTextColor(rh.gac(view.context, R.attr.defaultTextColor))
|
||||
} else {
|
||||
handleLevel(view, criticalSetting, criticalDefaultValue, warnSetting, warnDefaultValue, level, units)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
<item>DanaRv2</item>
|
||||
<item>DanaI</item>
|
||||
<item>Diaconn G8</item>
|
||||
<item>Eoflow Eopatch2</item>
|
||||
<item>Medtronic 512/712</item>
|
||||
<item>Medtronic 515/715</item>
|
||||
<item>Medtronic 522/722</item>
|
||||
|
|
|
@ -38,6 +38,9 @@ buildscript {
|
|||
androidx_junit_version = '1.1.3'
|
||||
androidx_rules_version = '1.4.0'
|
||||
|
||||
rxandroidble_version = '1.12.1'
|
||||
replayshare_version = '2.2.0'
|
||||
|
||||
wearable_version = '2.9.0'
|
||||
play_services_wearable_version = '17.1.0'
|
||||
play_services_location_version = '20.0.0'
|
||||
|
|
|
@ -98,6 +98,7 @@ sealed class ProfileSealed(
|
|||
override fun isValid(from: String, pump: Pump, config: Config, rh: ResourceHelper, rxBus: RxBus, hardLimits: HardLimits, sendNotifications: Boolean): Profile.ValidityCheck {
|
||||
val validityCheck = Profile.ValidityCheck()
|
||||
val description = pump.pumpDescription
|
||||
|
||||
for (basal in basalBlocks) {
|
||||
val basalAmount = basal.amount * percentage / 100.0
|
||||
if (!description.is30minBasalRatesCapable) {
|
||||
|
@ -142,6 +143,7 @@ sealed class ProfileSealed(
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!hardLimits.isInRange(dia, hardLimits.minDia(), hardLimits.maxDia())) {
|
||||
validityCheck.isValid = false
|
||||
validityCheck.reasons.add(rh.gs(R.string.value_out_of_hard_limits, rh.gs(R.string.profile_dia), dia))
|
||||
|
|
|
@ -17,7 +17,7 @@ interface CommandQueue {
|
|||
fun independentConnect(reason: String, callback: Callback?)
|
||||
fun bolusInQueue(): Boolean
|
||||
fun bolus(detailedBolusInfo: DetailedBolusInfo, callback: Callback?): Boolean
|
||||
fun cancelAllBoluses(id: Long)
|
||||
fun cancelAllBoluses(id: Long?)
|
||||
fun stopPump(callback: Callback?)
|
||||
fun startPump(callback: Callback?)
|
||||
fun setTBROverNotification(callback: Callback?, enable: Boolean)
|
||||
|
|
|
@ -10,5 +10,6 @@ enum class ManufacturerType(val description: String) {
|
|||
Cellnovo("Cellnovo"),
|
||||
Roche("Roche"),
|
||||
Ypsomed("Ypsomed"),
|
||||
G2e("G2e");
|
||||
G2e("G2e"),
|
||||
Eoflow("Eoflow");
|
||||
}
|
|
@ -130,6 +130,7 @@ open class Notification {
|
|||
const val MDT_INVALID_HISTORY_DATA = 76
|
||||
const val IDENTIFICATION_NOT_SET = 77
|
||||
const val PERMISSION_BT = 78
|
||||
const val EOELOW_PATCH_ALERTS = 79
|
||||
|
||||
const val USER_MESSAGE = 1000
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ enum class PumpCapability {
|
|||
OmnipodCapabilities(arrayOf(Bolus, TempBasal, BasalProfileSet, BasalRate30min)),
|
||||
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)),
|
||||
BasalRate_Duration15minAllowed,
|
||||
BasalRate_Duration30minAllowed,
|
||||
BasalRate_Duration15and30minAllowed(arrayOf(BasalRate_Duration15minAllowed, BasalRate_Duration30minAllowed)),
|
||||
|
|
|
@ -370,9 +370,25 @@ enum class PumpType {
|
|||
baseBasalStep = 0.01,
|
||||
baseBasalSpecialSteps = null,
|
||||
pumpCapability = PumpCapability.DiaconnCapabilities,
|
||||
source = Sources.DiaconnG8,
|
||||
useHardwareLink = true
|
||||
);
|
||||
source = Sources.DiaconnG8),
|
||||
|
||||
//EOPatch Pump
|
||||
EOFLOW_EOPATCH2(description = "Eoflow Eopatch2",
|
||||
manufacturer = ManufacturerType.Eoflow,
|
||||
model = "Eopatch",
|
||||
bolusSize = 0.05,
|
||||
specialBolusSize = null,
|
||||
extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05, 25.0),
|
||||
pumpTempBasalType = PumpTempBasalType.Absolute,
|
||||
tbrSettings = DoseSettings(0.05, 30, 12 * 60, 0.0, 15.0),
|
||||
specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed,
|
||||
baseBasalMinValue = 0.05,
|
||||
baseBasalMaxValue = 15.0,
|
||||
baseBasalStep = 0.05,
|
||||
baseBasalSpecialSteps = null,
|
||||
pumpCapability = PumpCapability.EopatchCapabilities,
|
||||
isPatchPump = true,
|
||||
source = Sources.EOPatch2);
|
||||
|
||||
val description: String
|
||||
var manufacturer: ManufacturerType? = null
|
||||
|
@ -460,7 +476,8 @@ enum class PumpType {
|
|||
InterfaceIDs.PumpType.MDI -> MDI
|
||||
InterfaceIDs.PumpType.USER -> USER
|
||||
InterfaceIDs.PumpType.DIACONN_G8 -> DIACONN_G8
|
||||
InterfaceIDs.PumpType.CACHE -> TODO()
|
||||
InterfaceIDs.PumpType.EOPATCH2 -> EOFLOW_EOPATCH2
|
||||
InterfaceIDs.PumpType.CACHE -> CACHE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,6 +608,7 @@ enum class PumpType {
|
|||
MDI -> InterfaceIDs.PumpType.MDI
|
||||
USER -> InterfaceIDs.PumpType.USER
|
||||
DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8
|
||||
EOFLOW_EOPATCH2 -> InterfaceIDs.PumpType.EOPATCH2
|
||||
CACHE -> InterfaceIDs.PumpType.CACHE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,6 +139,7 @@ class UserEntryMapper {
|
|||
Omnipod (UserEntry.Sources.Omnipod),
|
||||
OmnipodEros (UserEntry.Sources.OmnipodEros),
|
||||
OmnipodDash (UserEntry.Sources.OmnipodDash),
|
||||
EOPatch2 (UserEntry.Sources.EOPatch2),
|
||||
MDI (UserEntry.Sources.MDI),
|
||||
VirtualPump (UserEntry.Sources.VirtualPump),
|
||||
SMS (UserEntry.Sources.SMS),
|
||||
|
|
|
@ -95,6 +95,7 @@ class UserEntryPresentationHelper @Inject constructor(
|
|||
Sources.Omnipod -> R.drawable.ic_patch_pump_outline
|
||||
Sources.OmnipodEros -> R.drawable.ic_patch_pump_outline
|
||||
Sources.OmnipodDash -> R.drawable.ic_patch_pump_outline
|
||||
Sources.EOPatch2 -> R.drawable.ic_eopatch2_128
|
||||
Sources.MDI -> R.drawable.ic_ict
|
||||
Sources.VirtualPump -> R.drawable.ic_virtual_pump
|
||||
Sources.SMS -> R.drawable.ic_sms
|
||||
|
|
43
core/src/main/res/drawable/ic_eopatch2_128.xml
Normal file
43
core/src/main/res/drawable/ic_eopatch2_128.xml
Normal file
|
@ -0,0 +1,43 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:pathData="M0,0h128v128h-128z"
|
||||
android:strokeAlpha="0"
|
||||
android:fillColor="#fff"
|
||||
android:fillAlpha="0"/>
|
||||
<path
|
||||
android:pathData="M43.77,113.5C19.18,113.5 4.5,95 4.5,64c0,-41.4 11.62,-49.5 31.69,-49.5H81.77A41.68,41.68 0,0 1,123.5 56V88.17A25.43,25.43 0,0 1,98.05 113.5Z"
|
||||
android:fillColor="#f7f7f7"/>
|
||||
<path
|
||||
android:pathData="M81.77,15A41.18,41.18 0,0 1,123 56V88.17a24.92,24.92 0,0 1,-25 24.83H43.77c-11.64,0 -21.36,-4.36 -28.11,-12.62C8.69,91.85 5,79.27 5,64 5,23 16.43,15 36.19,15H81.77m0,-1H36.19C14.65,14 4,24 4,64c0,32 15.77,50 39.77,50H98.05a25.89,25.89 0,0 0,26 -25.83V56A42.14,42.14 0,0 0,81.77 14Z"
|
||||
android:fillColor="#424242"/>
|
||||
<path
|
||||
android:pathData="M81.59,29.5A26.35,26.35 0,0 1,108 55.72V88.19A10.36,10.36 0,0 1,97.61 98.5h-51c-7.54,0 -13,-1.76 -17.29,-5.53C23.13,87.51 20,77.76 20,64c0,-25.56 1.38,-34.5 16.79,-34.5h44.8m0,-1H36.79C20.58,28.5 19,38.22 19,64c0,31.93 16.49,35.5 27.59,35.5h51A11.35,11.35 0,0 0,109 88.19V55.72A27.32,27.32 0,0 0,81.59 28.5Z"
|
||||
android:fillColor="#424242"/>
|
||||
<path
|
||||
android:pathData="M84.39,57H95.61a0.29,0.29 0,0 0,0.25 -0.26,10.88 10.88,0 0,0 0,-3.48 0.29,0.29 0,0 0,-0.25 -0.26H84.39a0.29,0.29 0,0 0,-0.25 0.26,10.88 10.88,0 0,0 0,3.48A0.29,0.29 0,0 0,84.39 57Z"
|
||||
android:fillColor="#bdbdbd"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M90,55m-9,0a9,9 0,1 1,18 0a9,9 0,1 1,-18 0"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#bdbdbd"/>
|
||||
<path
|
||||
android:pathData="M85.5,107.5m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"
|
||||
android:strokeWidth="0.97"
|
||||
android:fillColor="#fff"
|
||||
android:strokeColor="#bdbdbd"/>
|
||||
<path
|
||||
android:pathData="M10.45,64m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"
|
||||
android:strokeWidth="0.97"
|
||||
android:fillColor="#fff"
|
||||
android:strokeColor="#bdbdbd"/>
|
||||
<path
|
||||
android:pathData="M85.5,20.5m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"
|
||||
android:strokeWidth="0.97"
|
||||
android:fillColor="#fff"
|
||||
android:strokeColor="#bdbdbd"/>
|
||||
</vector>
|
|
@ -43,6 +43,8 @@ files:
|
|||
translation: /insight/src/main/res/values-%android_code%/exceptions.xml
|
||||
- source: /automation/src/main/res/values/strings.xml
|
||||
translation: /automation/src/main/res/values-%android_code%/strings.xml
|
||||
- source: /pump/eopatch/src/main/res/values/strings.xml
|
||||
translation: /pump/eopatch/src/main/res/values-%android_code%/strings.xml
|
||||
- source: /pump/diaconn/src/main/res/values/strings.xml
|
||||
translation: /pump/diaconn/src/main/res/values-%android_code%/strings.xml
|
||||
- source: /pump/pump-common/src/main/res/values/strings.xml
|
||||
|
|
|
@ -42,6 +42,7 @@ data class InterfaceIDs(
|
|||
YPSOPUMP,
|
||||
MDI,
|
||||
DIACONN_G8,
|
||||
EOPATCH2,
|
||||
USER,
|
||||
CACHE;
|
||||
|
||||
|
|
|
@ -172,6 +172,7 @@ data class UserEntry(
|
|||
Omnipod, //No entry currently
|
||||
OmnipodEros,
|
||||
OmnipodDash, //No entry currently
|
||||
EOPatch2,
|
||||
MDI,
|
||||
VirtualPump,
|
||||
SMS, //From SMS plugin
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
org.gradle.parallel=true
|
||||
org.gradle.warning.mode=all
|
||||
org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC
|
||||
org.gradle.jvmargs=-Xmx3g -XX:+UseParallelGC
|
||||
|
||||
android.enableJetifier=false
|
||||
android.useAndroidX=true
|
||||
|
|
|
@ -348,7 +348,7 @@ class CommandQueueImplementation @Inject constructor(
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
override fun cancelAllBoluses(id: Long) {
|
||||
override fun cancelAllBoluses(id: Long?) {
|
||||
if (!isRunning(CommandType.BOLUS)) {
|
||||
rxBus.send(EventDismissBolusProgressIfRunning(PumpEnactResult(injector).success(true).enacted(false), id))
|
||||
}
|
||||
|
|
|
@ -41,7 +41,8 @@ project.afterEvaluate {
|
|||
'**/R2$*.class',
|
||||
'**/*Directions$*',
|
||||
'**/*Directions.*',
|
||||
'**/*Binding.*'
|
||||
'**/*Binding.*',
|
||||
'**/BR.class'
|
||||
]
|
||||
|
||||
def jClasses = subprojects.collect { proj ->
|
||||
|
|
1
pump/eopatch-core/.gitignore
vendored
Normal file
1
pump/eopatch-core/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
2
pump/eopatch-core/build.gradle
Normal file
2
pump/eopatch-core/build.gradle
Normal file
|
@ -0,0 +1,2 @@
|
|||
configurations.create("default")
|
||||
artifacts.add("default", file('libs/eopatch_core.aar'))
|
0
pump/eopatch-core/consumer-rules.pro
Normal file
0
pump/eopatch-core/consumer-rules.pro
Normal file
BIN
pump/eopatch-core/libs/eopatch_core.aar
Normal file
BIN
pump/eopatch-core/libs/eopatch_core.aar
Normal file
Binary file not shown.
21
pump/eopatch-core/proguard-rules.pro
vendored
Normal file
21
pump/eopatch-core/proguard-rules.pro
vendored
Normal file
|
@ -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
|
4
pump/eopatch-core/src/main/AndroidManifest.xml
Normal file
4
pump/eopatch-core/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
1
pump/eopatch/.gitignore
vendored
Normal file
1
pump/eopatch/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
30
pump/eopatch/build.gradle
Normal file
30
pump/eopatch/build.gradle
Normal file
|
@ -0,0 +1,30 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-allopen'
|
||||
apply plugin: 'com.hiya.jacoco-android'
|
||||
|
||||
apply from: "${project.rootDir}/core/android_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/android_module_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/test_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/jacoco_global.gradle"
|
||||
|
||||
android {
|
||||
namespace 'info.nightscout.androidaps.plugins.pump.eopatch'
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation project(':pump:eopatch-core')
|
||||
implementation project(':libraries')
|
||||
implementation project(':shared')
|
||||
implementation project(':database')
|
||||
implementation project(':core')
|
||||
|
||||
//RxAndroidBle
|
||||
implementation "com.polidea.rxandroidble3:rxandroidble:1.16.0"
|
||||
implementation "com.jakewharton.rx3:replaying-share:3.0.0"
|
||||
}
|
21
pump/eopatch/proguard-rules.pro
vendored
Normal file
21
pump/eopatch/proguard-rules.pro
vendored
Normal file
|
@ -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
|
11
pump/eopatch/src/main/AndroidManifest.xml
Normal file
11
pump/eopatch/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application>
|
||||
<activity android:name=".ui.EopatchActivity" />
|
||||
<activity android:name=".ui.AlarmHelperActivity" />
|
||||
<activity android:name=".ui.DialogHelperActivity" />
|
||||
<receiver android:name=".OsAlarmReceiver"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,30 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
interface AppConstant {
|
||||
companion object {
|
||||
const val BASAL_MIN_AMOUNT = 0.05f
|
||||
|
||||
const val INSULIN_UNIT_P = 0.05f
|
||||
|
||||
const val INSULIN_UNIT_STEP_U = INSULIN_UNIT_P
|
||||
|
||||
const val OFF = 0
|
||||
const val ON = 1
|
||||
|
||||
const val PUMP_DURATION_MILLI = 4 * 1000L
|
||||
|
||||
const val BASAL_RATE_PER_HOUR_MIN = BASAL_MIN_AMOUNT
|
||||
|
||||
const val SEGMENT_MAX_SIZE_48 = 48
|
||||
const val SEGMENT_COUNT_MAX = SEGMENT_MAX_SIZE_48
|
||||
|
||||
const val BOLUS_ACTIVE_EXTENDED_WAIT = 0x2
|
||||
|
||||
const val BOLUS_UNIT_STEP = INSULIN_UNIT_STEP_U
|
||||
|
||||
const val DAY_START_MINUTE = 0 * 60
|
||||
const val DAY_END_MINUTE = 24 * 60
|
||||
const val INSULIN_DURATION_MIN = 2.0f
|
||||
const val MAX_RESERVOIR_READING = 50.0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
|
||||
object CommonUtils {
|
||||
fun dispose(vararg disposable: Disposable?) {
|
||||
for (d in disposable){
|
||||
d?.let {
|
||||
if (!it.isDisposed) {
|
||||
it.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hasText(str: CharSequence?): Boolean {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
val strLen = str.length
|
||||
for (i in 0 until strLen) {
|
||||
if (!Character.isWhitespace(str[i])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun hasText(str: String?): Boolean {
|
||||
return str?.let{hasText(it as CharSequence)}?:false
|
||||
}
|
||||
|
||||
fun isStringEmpty(cs: CharSequence?): Boolean {
|
||||
return cs == null || cs.isEmpty()
|
||||
}
|
||||
|
||||
@JvmStatic fun dateString(millis: Long): String {
|
||||
if(millis == 0L) return ""
|
||||
|
||||
val c = Calendar.getInstance()
|
||||
c.timeInMillis = millis
|
||||
return dateString(c)
|
||||
}
|
||||
|
||||
fun dateString(c: Calendar): String {
|
||||
return String.format(Locale.US, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
c.get(Calendar.YEAR),
|
||||
c.get(Calendar.MONTH) + 1,
|
||||
c.get(Calendar.DAY_OF_MONTH),
|
||||
c.get(Calendar.HOUR_OF_DAY),
|
||||
c.get(Calendar.MINUTE),
|
||||
c.get(Calendar.SECOND))
|
||||
}
|
||||
|
||||
fun getRemainHourMin(timeMillis: Long): Pair<Long, Long> {
|
||||
val diffHours: Long
|
||||
var diffMinutes: Long
|
||||
|
||||
if (timeMillis >= 0) {
|
||||
diffMinutes = abs(timeMillis / (60 * 1000) % 60) + 1
|
||||
if (diffMinutes == 60L) {
|
||||
diffMinutes = 0
|
||||
diffHours = abs(timeMillis / (60 * 60 * 1000)) + 1
|
||||
} else {
|
||||
diffHours = abs(timeMillis / (60 * 60 * 1000))
|
||||
}
|
||||
} else {
|
||||
diffMinutes = abs(timeMillis / (60 * 1000) % 60)
|
||||
diffHours = abs(timeMillis / (60 * 60 * 1000))
|
||||
}
|
||||
return Pair(diffHours, diffMinutes)
|
||||
}
|
||||
|
||||
fun nearlyEqual(a: Float, b: Float, epsilon: Float): Boolean {
|
||||
val absA = abs(a)
|
||||
val absB = abs(b)
|
||||
val diff = abs(a - b)
|
||||
return if (a == b) {
|
||||
true
|
||||
} else if (a == 0f || b == 0f || absA + absB < java.lang.Float.MIN_NORMAL) {
|
||||
diff < epsilon * java.lang.Float.MIN_NORMAL
|
||||
} else {
|
||||
diff / min(absA + absB, Float.MAX_VALUE) < epsilon
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> clone(src: T): T {
|
||||
return GsonHelper.sharedGson().fromJson(GsonHelper.sharedGson().toJson(src), src.javaClass)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import javax.inject.Inject
|
||||
|
||||
class EONotification constructor() : Notification() {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
|
||||
constructor(id: Int, text: String, level: Int) : this() {
|
||||
this.id = id
|
||||
date = System.currentTimeMillis()
|
||||
this.text = text
|
||||
this.level = level
|
||||
}
|
||||
|
||||
fun action(buttonText: Int, action: Runnable) {
|
||||
this.buttonText = buttonText
|
||||
this.action = action
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
|
||||
object EoPatchRxBus {
|
||||
private val publishSubject: PublishSubject<Any> = PublishSubject.create()
|
||||
|
||||
fun publish(event: Any) {
|
||||
publishSubject.onNext(event)
|
||||
}
|
||||
|
||||
fun <T: Any> listen(eventType: Class<T>): Observable<T> {
|
||||
return publishSubject.ofType(eventType)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,562 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
import android.os.SystemClock
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.events.EventAppInitialized
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.interfaces.CommandQueue
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.interfaces.Pump
|
||||
import info.nightscout.androidaps.interfaces.PumpDescription
|
||||
import info.nightscout.androidaps.interfaces.PumpPluginBase
|
||||
import info.nightscout.androidaps.interfaces.PumpSync
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.common.ManufacturerType
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.IAlarmManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPatchManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.BolusExDuration
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.SettingKeys
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.EopatchOverviewFragment
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.TempBasal
|
||||
import info.nightscout.androidaps.queue.commands.CustomCommand
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.TimeChangeType
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.functions.Consumer
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Singleton
|
||||
class EopatchPumpPlugin @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 patchManager: IPatchManager,
|
||||
private val alarmManager: IAlarmManager,
|
||||
private val preferenceManager: IPreferenceManager
|
||||
):PumpPluginBase(PluginDescription()
|
||||
.mainType(PluginType.PUMP)
|
||||
.fragmentClass(EopatchOverviewFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_eopatch2_128)
|
||||
.pluginName(R.string.eopatch)
|
||||
.shortName(R.string.eopatch_shortname)
|
||||
.preferencesId(R.xml.pref_eopatch)
|
||||
.description(R.string.eopatch_pump_description), injector, aapsLogger, rh, commandQueue
|
||||
), Pump {
|
||||
|
||||
private val mDisposables = CompositeDisposable()
|
||||
|
||||
private var mPumpType: PumpType = PumpType.EOFLOW_EOPATCH2
|
||||
private var mLastDataTime: Long = 0
|
||||
private val mPumpDescription = PumpDescription(mPumpType)
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
mDisposables.add(rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventPreferenceChange ->
|
||||
if (event.isChanged(rh, SettingKeys.LOW_RESERVOIR_REMINDERS) || event.isChanged(rh, SettingKeys.EXPIRATION_REMINDERS)) {
|
||||
patchManager.changeReminderSetting()
|
||||
} else if (event.isChanged(rh, SettingKeys.BUZZER_REMINDERS)) {
|
||||
patchManager.changeBuzzerSetting()
|
||||
}
|
||||
}) { throwable: Throwable -> fabricPrivacy.logException(throwable) }
|
||||
)
|
||||
|
||||
mDisposables.add(rxBus
|
||||
.toObservable(EventAppInitialized::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
preferenceManager.init()
|
||||
patchManager.init()
|
||||
alarmManager.init()
|
||||
}) { throwable: Throwable -> fabricPrivacy.logException(throwable) }
|
||||
)
|
||||
}
|
||||
|
||||
override fun specialEnableCondition(): Boolean {
|
||||
//BG -> FG, restart patch activation and trigger unhandled alarm
|
||||
if(preferenceManager.isInitDone()) {
|
||||
patchManager.checkActivationProcess()
|
||||
alarmManager.restartAll()
|
||||
}
|
||||
return super.specialEnableCondition()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
aapsLogger.debug(LTag.PUMP, "EOPatchPumpPlugin onStop()")
|
||||
}
|
||||
|
||||
override fun isInitialized(): Boolean {
|
||||
return isConnected() && patchManager.isActivated
|
||||
}
|
||||
|
||||
override fun isSuspended(): Boolean {
|
||||
return patchManager.patchState.isNormalBasalPaused
|
||||
}
|
||||
|
||||
override fun isBusy(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isConnected(): Boolean {
|
||||
return if(patchManager.isDeactivated) true else patchManager.patchConnectionState.isConnected
|
||||
}
|
||||
|
||||
override fun isConnecting(): Boolean {
|
||||
return patchManager.patchConnectionState.isConnecting
|
||||
}
|
||||
|
||||
override fun isHandshakeInProgress(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun finishHandshaking() {
|
||||
}
|
||||
|
||||
override fun connect(reason: String) {
|
||||
aapsLogger.debug(LTag.PUMP,"EOPatch connect - reason:$reason")
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
override fun disconnect(reason: String) {
|
||||
aapsLogger.debug(LTag.PUMP,"EOPatch disconnect - reason:$reason")
|
||||
}
|
||||
|
||||
override fun stopConnecting() {
|
||||
}
|
||||
|
||||
override fun getPumpStatus(reason: String) {
|
||||
if (patchManager.isActivated) {
|
||||
if ("SMS" == reason) {
|
||||
aapsLogger.debug("Acknowledged AAPS getPumpStatus request it was requested through an SMS")
|
||||
}else{
|
||||
aapsLogger.debug("Acknowledged AAPS getPumpStatus request")
|
||||
}
|
||||
mDisposables.add(patchManager.updateConnection()
|
||||
.subscribe(Consumer {
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
if(patchManager.isActivated){
|
||||
if(patchManager.patchState.isTempBasalActive || patchManager.patchState.isBolusActive){
|
||||
return PumpEnactResult(injector)
|
||||
}else{
|
||||
var isSuccess: Boolean? = null
|
||||
val result: BehaviorSubject<Boolean> = BehaviorSubject.create()
|
||||
val disposable = result.hide()
|
||||
.subscribe {
|
||||
isSuccess = it
|
||||
}
|
||||
|
||||
val nb = preferenceManager.getNormalBasalManager().convertProfileToNormalBasal(profile)
|
||||
mDisposables.add(patchManager.startBasal(nb)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ response ->
|
||||
result.onNext(response.isSuccess)
|
||||
}, {
|
||||
result.onNext(false)
|
||||
})
|
||||
)
|
||||
|
||||
do{
|
||||
SystemClock.sleep(100)
|
||||
}while(isSuccess == null)
|
||||
|
||||
disposable.dispose()
|
||||
aapsLogger.info(LTag.PUMP, "Basal Profile was set: ${isSuccess?:false}")
|
||||
if(isSuccess == true) {
|
||||
rxBus.send(EventNewNotification(Notification(Notification.PROFILE_SET_OK, rh.gs(R.string.profile_set_ok), Notification.INFO, 60)))
|
||||
return PumpEnactResult(injector).success(true).enacted(true)
|
||||
}else{
|
||||
return PumpEnactResult(injector)
|
||||
}
|
||||
}
|
||||
}else{
|
||||
preferenceManager.getNormalBasalManager().setNormalBasal(profile)
|
||||
preferenceManager.flushNormalBasalManager()
|
||||
rxBus.send(EventNewNotification(Notification(Notification.PROFILE_SET_OK, rh.gs(R.string.profile_set_ok), Notification.INFO, 60)))
|
||||
return PumpEnactResult(injector).success(true).enacted(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||
// if (!patchManager.isActivated) {
|
||||
// return true
|
||||
// }
|
||||
|
||||
val ret = preferenceManager.getNormalBasalManager().isEqual(profile)
|
||||
aapsLogger.info(LTag.PUMP, "Is this profile set? $ret")
|
||||
return ret
|
||||
}
|
||||
|
||||
override fun lastDataTime(): Long {
|
||||
return mLastDataTime
|
||||
}
|
||||
|
||||
override val baseBasalRate: Double
|
||||
get() {
|
||||
if (!patchManager.isActivated || patchManager.patchState.isNormalBasalPaused) {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return preferenceManager.getNormalBasalManager().normalBasal.getCurrentSegment()?.doseUnitPerHour?.toDouble()?:0.05
|
||||
}
|
||||
|
||||
override val reservoirLevel: Double
|
||||
get() {
|
||||
if (!patchManager.isActivated) {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return patchManager.patchState.remainedInsulin.toDouble()
|
||||
}
|
||||
|
||||
override val batteryLevel: Int
|
||||
get() {
|
||||
return if(patchManager.isActivated) {
|
||||
patchManager.patchState.batteryLevel()
|
||||
}else{
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||
|
||||
if (detailedBolusInfo.insulin == 0.0 && detailedBolusInfo.carbs == 0.0) {
|
||||
// neither carbs nor bolus requested
|
||||
aapsLogger.error("deliverTreatment: Invalid input: neither carbs nor insulin are set in treatment")
|
||||
return PumpEnactResult(injector).success(false).enacted(false).bolusDelivered(0.0).carbsDelivered(0.0)
|
||||
.comment(rh.gs(R.string.invalidinput))
|
||||
} else if (detailedBolusInfo.insulin > 0.0) {
|
||||
var isSuccess = true
|
||||
val result = BehaviorSubject.createDefault(true)
|
||||
val disposable = result.hide()
|
||||
.subscribe {
|
||||
isSuccess = it
|
||||
}
|
||||
|
||||
mDisposables.add(patchManager.startCalculatorBolus(detailedBolusInfo)
|
||||
.doOnSuccess {
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
}.subscribe({
|
||||
result.onNext(it.isSuccess)
|
||||
}, {
|
||||
result.onNext(false)
|
||||
})
|
||||
)
|
||||
|
||||
val tr = detailedBolusInfo.let {
|
||||
EventOverviewBolusProgress.Treatment(it.insulin, it.carbs.toInt(), it.bolusType === DetailedBolusInfo.BolusType.SMB, it.id)
|
||||
}
|
||||
|
||||
do{
|
||||
SystemClock.sleep(100)
|
||||
if(patchManager.patchConnectionState.isConnected) {
|
||||
val delivering = patchManager.bolusCurrent.nowBolus.injected
|
||||
rxBus.send(EventOverviewBolusProgress.apply {
|
||||
status = rh.gs(R.string.bolusdelivering, delivering)
|
||||
percent = min((delivering / detailedBolusInfo.insulin * 100).toInt(), 100)
|
||||
t = tr
|
||||
})
|
||||
}
|
||||
}while(!patchManager.bolusCurrent.nowBolus.endTimeSynced && isSuccess)
|
||||
|
||||
rxBus.send(EventOverviewBolusProgress.apply {
|
||||
status = rh.gs(R.string.bolusdelivered, detailedBolusInfo.insulin)
|
||||
percent = 100
|
||||
})
|
||||
|
||||
detailedBolusInfo.insulin = patchManager.bolusCurrent.nowBolus.injected.toDouble()
|
||||
patchManager.addBolusToHistory(detailedBolusInfo)
|
||||
|
||||
disposable.dispose()
|
||||
|
||||
return if(isSuccess)
|
||||
PumpEnactResult(injector).success(true)/*.enacted(true)*/.carbsDelivered(detailedBolusInfo.carbs).bolusDelivered(detailedBolusInfo.insulin)
|
||||
else
|
||||
PumpEnactResult(injector).success(false)/*.enacted(false)*/.carbsDelivered(0.0).bolusDelivered(detailedBolusInfo.insulin)
|
||||
|
||||
} else {
|
||||
// no bolus required, carb only treatment
|
||||
patchManager.addBolusToHistory(detailedBolusInfo)
|
||||
|
||||
return PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(0.0)
|
||||
.carbsDelivered(detailedBolusInfo.carbs).comment(rh.gs(info.nightscout.androidaps.core.R.string.ok))
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopBolusDelivering() {
|
||||
mDisposables.add(patchManager.stopNowBolus()
|
||||
.subscribeOn(aapsSchedulers.io)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe { it ->
|
||||
rxBus.send(EventOverviewBolusProgress.apply {
|
||||
status = rh.gs(R.string.bolusdelivered, (it.injectedBolusAmount * 0.05f))
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
|
||||
aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute - absoluteRate: ${absoluteRate.toFloat()}, durationInMinutes: ${durationInMinutes.toLong()}, enforceNew: $enforceNew")
|
||||
if(patchManager.patchState.isNormalBasalAct){
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
val tb = TempBasal.createAbsolute(durationInMinutes.toLong(), absoluteRate.toFloat())
|
||||
return patchManager.startTempBasal(tb)
|
||||
.subscribeOn(aapsSchedulers.io)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.doOnSuccess {
|
||||
pumpSync.syncTemporaryBasalWithPumpId(
|
||||
timestamp = dateUtil.now(),
|
||||
rate = absoluteRate,
|
||||
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||
isAbsolute = true,
|
||||
type = tbrType,
|
||||
pumpId = dateUtil.now(),
|
||||
pumpType = PumpType.EOFLOW_EOPATCH2,
|
||||
pumpSerial = serialNumber()
|
||||
)
|
||||
aapsLogger.info(LTag.PUMP,"setTempBasalAbsolute - tbrCurrent:${readTBR()}")
|
||||
}
|
||||
.map { PumpEnactResult(injector).success(true).enacted(true).duration(durationInMinutes).absolute(absoluteRate).isPercent(false).isTempCancel(false) }
|
||||
.onErrorReturnItem(PumpEnactResult(injector).success(false).enacted(false)
|
||||
.comment("Internal error"))
|
||||
.blockingGet()
|
||||
}else{
|
||||
aapsLogger.info(LTag.PUMP,"setTempBasalAbsolute - normal basal is not active")
|
||||
return PumpEnactResult(injector).success(false).enacted(false)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
if(patchManager.patchState.isNormalBasalAct && percent != 0){
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
val tb = TempBasal.createPercent(durationInMinutes.toLong(), percent)
|
||||
return patchManager.startTempBasal(tb)
|
||||
.subscribeOn(aapsSchedulers.io)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.doOnSuccess {
|
||||
pumpSync.syncTemporaryBasalWithPumpId(
|
||||
timestamp = dateUtil.now(),
|
||||
rate = percent.toDouble(),
|
||||
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||
isAbsolute = false,
|
||||
type = tbrType,
|
||||
pumpId = dateUtil.now(),
|
||||
pumpType = PumpType.EOFLOW_EOPATCH2,
|
||||
pumpSerial = serialNumber()
|
||||
)
|
||||
aapsLogger.info(LTag.PUMP,"setTempBasalPercent - tbrCurrent:${readTBR()}")
|
||||
}
|
||||
.map { PumpEnactResult(injector).success(true).enacted(true).duration(durationInMinutes).percent(percent).isPercent(true).isTempCancel(false) }
|
||||
.onErrorReturnItem(PumpEnactResult(injector).success(false).enacted(false)
|
||||
.comment("Internal error"))
|
||||
.blockingGet()
|
||||
}else{
|
||||
aapsLogger.info(LTag.PUMP,"setTempBasalPercent - normal basal is not active")
|
||||
return PumpEnactResult(injector).success(false).enacted(false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
|
||||
aapsLogger.info(LTag.PUMP,"setExtendedBolus - insulin: $insulin, durationInMinutes: $durationInMinutes")
|
||||
|
||||
return patchManager.startQuickBolus(0f, insulin.toFloat(), BolusExDuration.ofRaw(durationInMinutes))
|
||||
.doOnSuccess {
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
pumpSync.syncExtendedBolusWithPumpId(
|
||||
timestamp = dateUtil.now(),
|
||||
amount = insulin,
|
||||
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||
isEmulatingTB = false,
|
||||
pumpId = dateUtil.now(),
|
||||
pumpType = PumpType.EOFLOW_EOPATCH2,
|
||||
pumpSerial = serialNumber()
|
||||
)
|
||||
}
|
||||
.map { PumpEnactResult(injector).success(true).enacted(true)}
|
||||
.onErrorReturnItem(PumpEnactResult(injector).success(false).enacted(false).bolusDelivered(0.0)
|
||||
.comment(rh.gs(info.nightscout.androidaps.core.R.string.error)))
|
||||
.blockingGet()
|
||||
}
|
||||
|
||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||
val tbrCurrent = readTBR()
|
||||
|
||||
if (tbrCurrent == null ) {
|
||||
aapsLogger.debug(LTag.PUMP,"cancelTempBasal - TBR already false.")
|
||||
return PumpEnactResult(injector).success(true).enacted(false)
|
||||
}
|
||||
|
||||
if (!patchManager.patchState.isTempBasalActive) {
|
||||
return if (pumpSync.expectedPumpState().temporaryBasal != null) {
|
||||
PumpEnactResult(injector).success(true).enacted(true).isTempCancel(true)
|
||||
}else
|
||||
PumpEnactResult(injector).success(true).isTempCancel(true)
|
||||
}
|
||||
|
||||
return patchManager.stopTempBasal()
|
||||
.doOnSuccess {
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
aapsLogger.debug(LTag.PUMP,"cancelTempBasal - $it")
|
||||
pumpSync.syncStopTemporaryBasalWithPumpId(
|
||||
timestamp = dateUtil.now(),
|
||||
endPumpId = dateUtil.now(),
|
||||
pumpType = PumpType.EOFLOW_EOPATCH2,
|
||||
pumpSerial = serialNumber()
|
||||
)
|
||||
}
|
||||
.doOnError{
|
||||
aapsLogger.error(LTag.PUMP,"cancelTempBasal() - $it")
|
||||
}
|
||||
.map { PumpEnactResult(injector).success(true).enacted(true).isTempCancel(true)}
|
||||
.onErrorReturnItem(PumpEnactResult(injector).success(false).enacted(false)
|
||||
.comment(rh.gs(info.nightscout.androidaps.core.R.string.error)))
|
||||
.blockingGet()
|
||||
}
|
||||
|
||||
override fun cancelExtendedBolus(): PumpEnactResult {
|
||||
if(patchManager.patchState.isExtBolusActive){
|
||||
return patchManager.stopExtBolus()
|
||||
.doOnSuccess {
|
||||
aapsLogger.debug(LTag.PUMP,"cancelExtendedBolus - success")
|
||||
mLastDataTime = System.currentTimeMillis()
|
||||
pumpSync.syncStopExtendedBolusWithPumpId(
|
||||
timestamp = dateUtil.now(),
|
||||
endPumpId = dateUtil.now(),
|
||||
pumpType = PumpType.EOFLOW_EOPATCH2,
|
||||
pumpSerial = serialNumber()
|
||||
)
|
||||
}
|
||||
.map { PumpEnactResult(injector).success(true).enacted(true).isTempCancel(true)}
|
||||
.onErrorReturnItem(PumpEnactResult(injector).success(false).enacted(false)
|
||||
.comment(rh.gs(info.nightscout.androidaps.core.R.string.error)))
|
||||
.blockingGet()
|
||||
}else{
|
||||
aapsLogger.debug(LTag.PUMP,"cancelExtendedBolus - nothing stops")
|
||||
return if (pumpSync.expectedPumpState().extendedBolus != null) {
|
||||
pumpSync.syncStopExtendedBolusWithPumpId(
|
||||
timestamp = dateUtil.now(),
|
||||
endPumpId = dateUtil.now(),
|
||||
pumpType = PumpType.EOFLOW_EOPATCH2,
|
||||
pumpSerial = serialNumber()
|
||||
)
|
||||
PumpEnactResult(injector).success(true).enacted(true).isTempCancel(true)
|
||||
}else
|
||||
PumpEnactResult(injector)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
|
||||
return JSONObject()
|
||||
}
|
||||
|
||||
override fun manufacturer(): ManufacturerType {
|
||||
return ManufacturerType.Eoflow
|
||||
}
|
||||
|
||||
override fun model(): PumpType {
|
||||
return PumpType.EOFLOW_EOPATCH2
|
||||
}
|
||||
|
||||
override fun serialNumber(): String {
|
||||
return patchManager.patchConfig.patchSerialNumber
|
||||
}
|
||||
|
||||
override val pumpDescription: PumpDescription
|
||||
get() = mPumpDescription
|
||||
|
||||
override fun shortStatus(veryShort: Boolean): String {
|
||||
if(patchManager.isActivated) {
|
||||
var ret = ""
|
||||
val activeTemp = pumpSync.expectedPumpState().temporaryBasal
|
||||
if (activeTemp != null)
|
||||
ret += "Temp: ${activeTemp.rate} U/hr"
|
||||
|
||||
val activeExtendedBolus = pumpSync.expectedPumpState().extendedBolus
|
||||
if (activeExtendedBolus != null)
|
||||
ret += "Extended: ${activeExtendedBolus.amount} U\n"
|
||||
|
||||
val reservoirStr = patchManager.patchState.remainedInsulin.let {
|
||||
when {
|
||||
it > 50f -> "50+ U"
|
||||
it < 1f -> "0 U"
|
||||
else -> "${it.roundToInt()} U"
|
||||
}
|
||||
}
|
||||
|
||||
ret += "Reservoir: $reservoirStr"
|
||||
ret += "Battery: ${patchManager.patchState.batteryLevel()}"
|
||||
return ret
|
||||
}else{
|
||||
return "EOPatch is not enabled."
|
||||
}
|
||||
}
|
||||
|
||||
override val isFakingTempsByExtendedBoluses: Boolean = false
|
||||
|
||||
override fun loadTDDs(): PumpEnactResult {
|
||||
return PumpEnactResult(injector)
|
||||
}
|
||||
|
||||
override fun canHandleDST(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getCustomActions(): List<CustomAction>? {
|
||||
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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
object FloatFormatters {
|
||||
val INSULIN = Function<Number, String>{ value -> String.format(Locale.US, "%.2f", value.toFloat()) }
|
||||
val FAT = Function<Number, String>{ value -> String.format(Locale.US, "%.1f", value.toFloat()) }
|
||||
val DURATION = Function<Number, String>{ value -> String.format(Locale.US, "%.1f", value.toFloat()) }
|
||||
|
||||
fun insulin(value: Float): String {
|
||||
return INSULIN.apply(value)
|
||||
}
|
||||
|
||||
fun insulin(value: Float, suffix: String?): String {
|
||||
return if (CommonUtils.isStringEmpty(suffix)) {
|
||||
INSULIN.apply(value)
|
||||
} else {
|
||||
INSULIN.apply(value) +" "+ suffix!!
|
||||
}
|
||||
}
|
||||
|
||||
fun duration(value: Float): String {
|
||||
return DURATION.apply(value)
|
||||
}
|
||||
|
||||
fun duration(value: Float, suffix: String?): String {
|
||||
return if (CommonUtils.isStringEmpty(suffix)) {
|
||||
DURATION.apply(value)
|
||||
} else {
|
||||
DURATION.apply(value) +" " + suffix!!
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
|
||||
object GsonHelper {
|
||||
private var defaultGson: Gson? = null
|
||||
|
||||
init {
|
||||
defaultGson = GsonBuilder().serializeSpecialFloatingPointValues().create()
|
||||
}
|
||||
|
||||
fun sharedGson(): Gson {
|
||||
if (defaultGson == null) {
|
||||
throw RuntimeException("Not configured gson")
|
||||
}
|
||||
|
||||
return defaultGson!!
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import dagger.android.DaggerBroadcastReceiver
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.Companion.fromIntent
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.event.EventEoPatchAlarm
|
||||
|
||||
class OsAlarmReceiver : DaggerBroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
super.onReceive(context, intent)
|
||||
fromIntent(intent)?.let { alarmCode ->
|
||||
EoPatchRxBus.publish(EventEoPatchAlarm(HashSet<AlarmCode>().apply { add(alarmCode) }))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
|
||||
public class OsAlarmService extends Service {
|
||||
|
||||
public static final int FOREGROUND_NOTIFICATION_ID = 34534554;
|
||||
|
||||
private CompositeDisposable compositeDisposable;
|
||||
|
||||
private boolean foreground = false;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
compositeDisposable = new CompositeDisposable();
|
||||
|
||||
startForeground();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
startForeground();
|
||||
|
||||
String action = null;
|
||||
|
||||
if (action == null) {
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
((NotificationManager) Objects.requireNonNull(getSystemService(Context.NOTIFICATION_SERVICE))).cancel(FOREGROUND_NOTIFICATION_ID);
|
||||
|
||||
compositeDisposable.dispose();
|
||||
}
|
||||
|
||||
public synchronized void startForeground() {
|
||||
if (!foreground) {
|
||||
foreground = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void start(Context context) {
|
||||
Intent intent = new Intent(context, OsAlarmService.class);
|
||||
|
||||
// context.startForegroundService(intent);
|
||||
}
|
||||
|
||||
public static void notifyNotification(Context context, boolean isNetworkAvailable) {
|
||||
notifyNotification(context);
|
||||
}
|
||||
|
||||
public static void notifyNotification(Context context) {
|
||||
// Notification builder = getNotification(context);
|
||||
// ((NotificationManager) Objects.requireNonNull(context.getSystemService(Context.NOTIFICATION_SERVICE))).notify(FOREGROUND_NOTIFICATION_ID, builder);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
@file:Suppress("unused")
|
||||
|
||||
package info.nightscout.androidaps.plugins.pump.eopatch
|
||||
|
||||
import android.os.SystemClock
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import io.reactivex.rxjava3.core.Scheduler
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class RxAction @Inject constructor(
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val aapsLogger: AAPSLogger
|
||||
) {
|
||||
enum class RxVoid {
|
||||
INSTANCE
|
||||
}
|
||||
|
||||
private fun sleep(millis: Long) {
|
||||
if (millis <= 0)
|
||||
return
|
||||
SystemClock.sleep(millis)
|
||||
}
|
||||
|
||||
private fun delay(delayMs: Long): Single<*> {
|
||||
return if (delayMs <= 0) {
|
||||
Single.just(1)
|
||||
} else Single.timer(delayMs, TimeUnit.MILLISECONDS)
|
||||
|
||||
}
|
||||
|
||||
fun single(action: Runnable, delayMs: Long, scheduler: Scheduler): Single<*> {
|
||||
return delay(delayMs)
|
||||
.observeOn(scheduler)
|
||||
.flatMap {
|
||||
Single.fromCallable {
|
||||
action.run()
|
||||
RxVoid.INSTANCE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun runOnMainThread(action: Runnable, delayMs: Long = 0) {
|
||||
single(action, delayMs, aapsSchedulers.main)
|
||||
.subscribe({
|
||||
|
||||
},
|
||||
{ e ->
|
||||
aapsLogger.error("SilentObserver.onError() ignore", e)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.alarm
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.R
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.AlarmCategory
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
import java.util.stream.Collectors
|
||||
import java.util.stream.Stream
|
||||
|
||||
enum class AlarmCode(messageResId: Int) {
|
||||
A002(R.string.string_a002), //"Empty reservoir"
|
||||
A003(R.string.string_a003), //"Patch expired"
|
||||
A004(R.string.string_a004), //"Occlusion"
|
||||
A005(R.string.string_a005), //"Power on self test failure"
|
||||
A007(R.string.string_a007), //"Inappropriate temperature"
|
||||
A016(R.string.string_a016), //"Needle insertion Error"
|
||||
A018(R.string.string_a018), //"Patch battery Error"
|
||||
A019(R.string.string_a019), //"Patch battery Error"
|
||||
A020(R.string.string_a020), //"Patch activation Error"
|
||||
A022(R.string.string_a022), //"Patch Error"
|
||||
A023(R.string.string_a023), //"Patch Error"
|
||||
A034(R.string.string_a034), //"Patch Error"
|
||||
A041(R.string.string_a041), //"Patch Error"
|
||||
A042(R.string.string_a042), //"Patch Error"
|
||||
A043(R.string.string_a043), //"Patch Error"
|
||||
A044(R.string.string_a044), //"Patch Error"
|
||||
A106(R.string.string_a106), //"Patch Error"
|
||||
A107(R.string.string_a107), //"Patch Error"
|
||||
A108(R.string.string_a108), //"Patch Error"
|
||||
A116(R.string.string_a116), //"Patch Error"
|
||||
A117(R.string.string_a117), //"Patch Error"
|
||||
A118(R.string.string_a118), //"Patch Error"
|
||||
B000(R.string.string_b000),
|
||||
B001(R.string.string_b001), //"End of insulin suspend"
|
||||
B003(R.string.string_b003), //"Low reservoir"
|
||||
B005(R.string.string_b005), //"Patch operating life expired"
|
||||
B006(R.string.string_b006), //"Patch will expire soon"
|
||||
B012(R.string.string_b012), //"Incomplete Patch activation"
|
||||
B018(R.string.string_b018); //"Patch battery low"
|
||||
|
||||
val type: Char = name[0]
|
||||
val code: Int = name.substring(1).toInt()
|
||||
val resId: Int = messageResId
|
||||
|
||||
val alarmCategory: AlarmCategory
|
||||
get() = when (type) {
|
||||
TYPE_ALARM -> AlarmCategory.ALARM
|
||||
TYPE_ALERT -> AlarmCategory.ALERT
|
||||
else -> AlarmCategory.NONE
|
||||
}
|
||||
|
||||
val aeCode: Int
|
||||
get() {
|
||||
when (type) {
|
||||
TYPE_ALARM -> return code + 100
|
||||
TYPE_ALERT -> return code
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
val isPatchOccurrenceAlert: Boolean
|
||||
get() = this == B003 || this == B005 || this == B006 || this == B018
|
||||
|
||||
val isPatchOccurrenceAlarm: Boolean
|
||||
get() = this == A002 || this == A003 || this == A004 || this == A018 || this == A019 || this == A022
|
||||
|| this == A023 || this == A034 || this == A041 || this == A042 || this == A043 || this == A044 || this == A106
|
||||
|| this == A107 || this == A108 || this == A116 || this == A117 || this == A118
|
||||
|
||||
companion object {
|
||||
const val TYPE_ALARM = 'A'
|
||||
const val TYPE_ALERT = 'B'
|
||||
|
||||
private const val SCHEME = "alarmkey"
|
||||
private const val ALARM_KEY_PATH = "alarmkey"
|
||||
private const val QUERY_CODE = "alarmcode"
|
||||
|
||||
private val NAME_MAP = Stream.of(*values())
|
||||
.collect(Collectors.toMap({ obj: AlarmCode -> obj.name }, Function.identity()))
|
||||
|
||||
fun fromStringToCode(name: String): AlarmCode? {
|
||||
return NAME_MAP[name]
|
||||
}
|
||||
|
||||
fun findByPatchAeCode(aeCode: Int): AlarmCode? {
|
||||
return if (aeCode > 100) {
|
||||
fromStringToCode(String.format(Locale.US, "A%03d", aeCode - 100))
|
||||
} else fromStringToCode(String.format(Locale.US, "B%03d", aeCode))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUri(alarmCode: AlarmCode): Uri {
|
||||
return Uri.Builder()
|
||||
.scheme(SCHEME)
|
||||
.authority("info.nightscout.androidaps")
|
||||
.path(ALARM_KEY_PATH)
|
||||
.appendQueryParameter(QUERY_CODE, alarmCode.name)
|
||||
.build()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getAlarmCode(uri: Uri): AlarmCode? {
|
||||
if (SCHEME == uri.scheme && ALARM_KEY_PATH == uri.lastPathSegment) {
|
||||
val code = uri.getQueryParameter(QUERY_CODE)
|
||||
if (code.isNullOrBlank()) {
|
||||
return null
|
||||
}
|
||||
return fromStringToCode(code)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun fromIntent(intent: Intent): AlarmCode? {
|
||||
return intent.data?.let { getAlarmCode(it) }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.alarm
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.CommandQueue
|
||||
import info.nightscout.androidaps.interfaces.PumpSync
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.EONotification
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.EoPatchRxBus
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.R
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.A005
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.A016
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.A020
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.B000
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.B001
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.B012
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPatchManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.AlarmCategory
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.event.EventEoPatchAlarm
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.AlarmHelperActivity
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.Alarms
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.max
|
||||
|
||||
interface IAlarmManager {
|
||||
fun init()
|
||||
fun restartAll()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
class AlarmManager @Inject constructor() : IAlarmManager {
|
||||
@Inject lateinit var patchManager: IPatchManager
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var commandQueue: CommandQueue
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var context: Context
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
|
||||
@Inject lateinit var pm: IPreferenceManager
|
||||
@Inject lateinit var mAlarmRegistry: IAlarmRegistry
|
||||
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var pumpSync: PumpSync
|
||||
|
||||
private lateinit var mAlarmProcess: AlarmProcess
|
||||
|
||||
private var compositeDisposable: CompositeDisposable = CompositeDisposable()
|
||||
private var alarmDisposable: Disposable? = null
|
||||
|
||||
@Inject
|
||||
fun onInit() {
|
||||
mAlarmProcess = AlarmProcess(patchManager, rxBus)
|
||||
}
|
||||
|
||||
override fun init(){
|
||||
alarmDisposable = EoPatchRxBus.listen(EventEoPatchAlarm::class.java)
|
||||
.map { it.alarmCodes }
|
||||
.doOnNext { aapsLogger.info(LTag.PUMP,"EventEoPatchAlarm Received") }
|
||||
.concatMap {
|
||||
Observable.fromArray(it)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribeOn(aapsSchedulers.main)
|
||||
.doOnNext { alarmCodes ->
|
||||
alarmCodes.forEach { alarmCode ->
|
||||
aapsLogger.info(LTag.PUMP,"alarmCode: ${alarmCode.name}")
|
||||
val valid = isValid(alarmCode)
|
||||
if (valid) {
|
||||
if (alarmCode.alarmCategory == AlarmCategory.ALARM || alarmCode == B012) {
|
||||
showAlarmDialog(alarmCode)
|
||||
} else {
|
||||
showNotification(alarmCode)
|
||||
}
|
||||
|
||||
updateState(alarmCode, AlarmState.FIRED)
|
||||
}else{
|
||||
updateState(alarmCode, AlarmState.HANDLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.subscribe({}, { throwable: Throwable -> fabricPrivacy.logException(throwable) })
|
||||
}
|
||||
|
||||
override fun restartAll() {
|
||||
val now = System.currentTimeMillis()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val occurredAlarm= pm.getAlarms().occurred.clone() as HashMap<AlarmCode, Alarms.AlarmItem>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val registeredAlarm = pm.getAlarms().registered.clone() as HashMap<AlarmCode, Alarms.AlarmItem>
|
||||
compositeDisposable.clear()
|
||||
if(occurredAlarm.isNotEmpty()){
|
||||
EoPatchRxBus.publish(EventEoPatchAlarm(occurredAlarm.keys))
|
||||
}
|
||||
|
||||
if(registeredAlarm.isNotEmpty()){
|
||||
registeredAlarm.forEach { raEntry ->
|
||||
compositeDisposable.add(
|
||||
mAlarmRegistry.add(raEntry.key, max(OS_REGISTER_GAP, raEntry.value.triggerTimeMilli - now))
|
||||
.subscribe()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValid(code: AlarmCode): Boolean{
|
||||
return when(code){
|
||||
A005, A016, A020, B012 -> {
|
||||
aapsLogger.info(LTag.PUMP,"Is $code valid? ${pm.getPatchConfig().hasMacAddress() && pm.getPatchConfig().lifecycleEvent.isSubStepRunning}")
|
||||
pm.getPatchConfig().hasMacAddress() && pm.getPatchConfig().lifecycleEvent.isSubStepRunning
|
||||
}
|
||||
else -> {
|
||||
aapsLogger.info(LTag.PUMP,"Is $code valid? ${pm.getPatchConfig().isActivated}")
|
||||
pm.getPatchConfig().isActivated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAlarmDialog(alarmCode: AlarmCode){
|
||||
val i = Intent(context, AlarmHelperActivity::class.java)
|
||||
i.putExtra("soundid", R.raw.error)
|
||||
i.putExtra("code", alarmCode.name)
|
||||
i.putExtra("status", resourceHelper.gs(alarmCode.resId))
|
||||
i.putExtra("title", resourceHelper.gs(R.string.string_alarm))
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context.startActivity(i)
|
||||
}
|
||||
|
||||
private fun showNotification(alarmCode: AlarmCode, timeOffset: Long = 0L){
|
||||
var alarmMsg = resourceHelper.gs(alarmCode.resId)
|
||||
if(alarmCode == B000){
|
||||
val expireTimeValue = pm.getPatchWakeupTimestamp() + TimeUnit.HOURS.toMillis(84)
|
||||
val expireTimeString = SimpleDateFormat(resourceHelper.gs(R.string.date_format_yyyy_m_d_e_a_hh_mm_comma), Locale.US).format(expireTimeValue)
|
||||
alarmMsg = resourceHelper.gs(alarmCode.resId, expireTimeString)
|
||||
}
|
||||
val notification = EONotification(Notification.EOELOW_PATCH_ALERTS + (alarmCode.aeCode + 10000), alarmMsg, Notification.URGENT)
|
||||
|
||||
notification.action(R.string.confirm) {
|
||||
compositeDisposable.add(
|
||||
Single.just(isValid(alarmCode))
|
||||
.flatMap { isValid ->
|
||||
return@flatMap if(isValid) mAlarmProcess.doAction(context, alarmCode)
|
||||
else Single.just(IAlarmProcess.ALARM_HANDLED)
|
||||
}
|
||||
.subscribe { ret ->
|
||||
if(ret == IAlarmProcess.ALARM_HANDLED){
|
||||
if(alarmCode == B001){
|
||||
pumpSync.syncStopTemporaryBasalWithPumpId(
|
||||
timestamp = dateUtil.now(),
|
||||
endPumpId = dateUtil.now(),
|
||||
pumpType = PumpType.EOFLOW_EOPATCH2,
|
||||
pumpSerial = patchManager.patchConfig.patchSerialNumber
|
||||
)
|
||||
}
|
||||
updateState(alarmCode, AlarmState.HANDLE)
|
||||
}else{
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
}
|
||||
})
|
||||
}
|
||||
notification.soundId = R.raw.error
|
||||
notification.date = pm.getPatchConfig().patchWakeupTimestamp + TimeUnit.SECONDS.toMillis(timeOffset)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
}
|
||||
|
||||
private fun updateState(alarmCode: AlarmCode, state: AlarmState){
|
||||
when(state){
|
||||
AlarmState.REGISTER -> pm.getAlarms().register(alarmCode, 0)
|
||||
AlarmState.FIRED -> pm.getAlarms().occurred(alarmCode)
|
||||
AlarmState.HANDLE -> pm.getAlarms().handle(alarmCode)
|
||||
}
|
||||
pm.flushAlarms()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val OS_REGISTER_GAP = 3 * 1000L
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.alarm
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.EopatchActivity.Companion.createIntentForCheckConnection
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.EopatchActivity.Companion.createIntentForDiscarded
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.EopatchActivity.Companion.createIntentForCannulaInsertionError
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPatchManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.*
|
||||
import android.content.Intent
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.R
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.EopatchActivity
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BaseResponse
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TemperatureResponse
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.event.EventDialog
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.event.EventProgressDialog
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.extension.takeOne
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.dialogs.CommonDialog
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import java.lang.Exception
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
interface IAlarmProcess {
|
||||
fun doAction(context: Context, code: AlarmCode): Single<Int>
|
||||
|
||||
companion object {
|
||||
const val ALARM_UNHANDLED = 0
|
||||
const val ALARM_PAUSE = 1
|
||||
const val ALARM_HANDLED = 2
|
||||
}
|
||||
}
|
||||
|
||||
class AlarmProcess(val patchManager: IPatchManager, val rxBus: RxBus) : IAlarmProcess {
|
||||
override fun doAction(context: Context, code: AlarmCode): Single<Int> {
|
||||
return when (code) {
|
||||
B001 -> resumeBasalAction(context)
|
||||
A002, A003, A004, A005, A018, A019,
|
||||
A020, A022, A023, A034, A041, A042,
|
||||
A043, A044, A106, A107, A108, A116,
|
||||
A117, A118 -> patchDeactivationAction(context)
|
||||
A007 -> inappropriateTemperatureAction(context)
|
||||
A016 -> needleInsertionErrorAction(context)
|
||||
B000, B003, B018 -> Single.just(IAlarmProcess.ALARM_HANDLED)
|
||||
B005, B006 -> Single.just(IAlarmProcess.ALARM_HANDLED)
|
||||
B012 -> Single.just(IAlarmProcess.ALARM_HANDLED)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startActivityWithSingleTop(context: Context, intent: Intent) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
private fun showCommunicationFailedDialog(onConfirmed: Runnable) {
|
||||
val dialog = CommonDialog().apply {
|
||||
title = R.string.patch_communication_failed
|
||||
message = R.string.patch_communication_check_helper_1
|
||||
positiveBtn = R.string.string_communication_check
|
||||
positiveListener = DialogInterface.OnClickListener { _, _ ->
|
||||
onConfirmed.run()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
rxBus.send(EventDialog(dialog, true))
|
||||
}
|
||||
|
||||
private fun actionWithPatchCheckConnection(context: Context, action: Callable<Single<Int>>): Single<Int> {
|
||||
return if (patchManager.patchConnectionState.isConnected) {
|
||||
try {
|
||||
action.call()
|
||||
} catch (e: Exception) {
|
||||
Single.just(IAlarmProcess.ALARM_PAUSE)
|
||||
}
|
||||
} else {
|
||||
Single.fromCallable {
|
||||
showCommunicationFailedDialog {
|
||||
startActivityWithSingleTop(context,
|
||||
createIntentForCheckConnection(context, goHomeAfterDiscard = true, forceDiscard = true))
|
||||
}
|
||||
IAlarmProcess.ALARM_PAUSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resumeBasalAction(context: Context): Single<Int> {
|
||||
return actionWithPatchCheckConnection(context) {
|
||||
patchManager.resumeBasal()
|
||||
.map { obj: BaseResponse -> obj.isSuccess }
|
||||
.flatMap { Single.just(it.takeOne(IAlarmProcess.ALARM_HANDLED, IAlarmProcess.ALARM_UNHANDLED)) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun patchDeactivationAction(context: Context): Single<Int> {
|
||||
return actionWithPatchCheckConnection(context) {
|
||||
rxBus.send(EventProgressDialog(true, R.string.string_in_progress))
|
||||
patchManager.deactivate(6000, true)
|
||||
.doFinally {
|
||||
rxBus.send(EventProgressDialog(false, R.string.string_in_progress))
|
||||
startActivityWithSingleTop(context, createIntentForDiscarded(context))
|
||||
}
|
||||
.flatMap { Single.just(IAlarmProcess.ALARM_HANDLED) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun needleInsertionErrorAction(context: Context): Single<Int> {
|
||||
return Single.fromCallable {
|
||||
startActivityWithSingleTop(context, createIntentForCannulaInsertionError(context))
|
||||
IAlarmProcess.ALARM_HANDLED
|
||||
}
|
||||
}
|
||||
|
||||
private fun inappropriateTemperatureAction(context: Context): Single<Int> {
|
||||
return actionWithPatchCheckConnection(context) {
|
||||
patchManager.temperature
|
||||
.map(TemperatureResponse::getTemperature)
|
||||
.map { temp -> (temp >= EopatchActivity.NORMAL_TEMPERATURE_MIN && temp <= EopatchActivity.NORMAL_TEMPERATURE_MAX) }
|
||||
.filter{ok -> ok}
|
||||
.flatMap { patchManager.resumeBasal().map { it.isSuccess.takeOne(IAlarmProcess.ALARM_HANDLED, IAlarmProcess.ALARM_UNHANDLED) }.toMaybe() }
|
||||
.defaultIfEmpty(IAlarmProcess.ALARM_UNHANDLED)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.alarm
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.AlarmManager.AlarmClockInfo
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.EoPatchRxBus
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.OsAlarmReceiver
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode.Companion.getUri
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.PatchLifecycle
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.code.PatchAeCode
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.event.EventEoPatchAlarm
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import io.reactivex.rxjava3.core.Maybe
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
interface IAlarmRegistry {
|
||||
fun add(alarmCode: AlarmCode, triggerAfter: Long, isFirst: Boolean = false): Maybe<AlarmCode>
|
||||
fun add(patchAeCodes: Set<PatchAeCode>)
|
||||
fun remove(alarmCode: AlarmCode): Maybe<AlarmCode>
|
||||
}
|
||||
|
||||
@Singleton
|
||||
class AlarmRegistry @Inject constructor() : IAlarmRegistry {
|
||||
@Inject lateinit var mContext: Context
|
||||
@Inject lateinit var pm: IPreferenceManager
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
|
||||
private lateinit var mOsAlarmManager: AlarmManager
|
||||
private var mDisposable: Disposable? = null
|
||||
private var compositeDisposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
@Inject fun onInit() {
|
||||
mOsAlarmManager = mContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
mDisposable = pm.observePatchLifeCycle()
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe {
|
||||
when(it){
|
||||
PatchLifecycle.REMOVE_NEEDLE_CAP -> {
|
||||
val triggerAfter = pm.getPatchConfig().patchWakeupTimestamp + TimeUnit.HOURS.toMillis(1) - System.currentTimeMillis()
|
||||
compositeDisposable.add(add(AlarmCode.A020, triggerAfter).subscribe())
|
||||
}
|
||||
PatchLifecycle.ACTIVATED -> {
|
||||
|
||||
}
|
||||
PatchLifecycle.SHUTDOWN -> {
|
||||
val sources = ArrayList<Maybe<*>>()
|
||||
sources.add(Maybe.just(true))
|
||||
pm.getAlarms().occurred.let{ occurredAlarms ->
|
||||
if(occurredAlarms.isNotEmpty()){
|
||||
occurredAlarms.keys.forEach { alarmCode ->
|
||||
sources.add(
|
||||
Maybe.just(alarmCode)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.doOnSuccess { rxBus.send(EventDismissNotification(Notification.EOELOW_PATCH_ALERTS + (alarmCode.aeCode + 10000))) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
pm.getAlarms().registered.let{ registeredAlarms ->
|
||||
if(registeredAlarms.isNotEmpty()){
|
||||
registeredAlarms.keys.forEach { alarmCode ->
|
||||
sources.add(remove(alarmCode))
|
||||
}
|
||||
}
|
||||
}
|
||||
compositeDisposable.add(Maybe.concat(sources)
|
||||
.subscribe {
|
||||
pm.getAlarms().clear()
|
||||
pm.flushAlarms()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun add(alarmCode: AlarmCode, triggerAfter: Long, isFirst: Boolean): Maybe<AlarmCode> {
|
||||
if(pm.getAlarms().occurred.containsKey(alarmCode)){
|
||||
return Maybe.just(alarmCode)
|
||||
}else {
|
||||
val triggerTimeMilli = System.currentTimeMillis() + triggerAfter
|
||||
pm.getAlarms().register(alarmCode, triggerAfter)
|
||||
pm.flushAlarms()
|
||||
if (triggerAfter <= 0L) {
|
||||
EoPatchRxBus.publish(EventEoPatchAlarm(HashSet<AlarmCode>().apply { add(alarmCode) }, isFirst))
|
||||
return Maybe.just(alarmCode)
|
||||
}
|
||||
return registerOsAlarm(alarmCode, triggerTimeMilli)
|
||||
}
|
||||
}
|
||||
|
||||
override fun add(patchAeCodes: Set<PatchAeCode>) {
|
||||
compositeDisposable.add(
|
||||
Observable.fromIterable(patchAeCodes)
|
||||
.filter{patchAeCodeItem -> AlarmCode.findByPatchAeCode(patchAeCodeItem.aeValue) != null}
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.filter { aeCodes -> AlarmCode.findByPatchAeCode(aeCodes.aeValue) != null }
|
||||
.flatMapMaybe{aeCodeResponse -> add(AlarmCode.findByPatchAeCode(aeCodeResponse.aeValue)!!, 0L, true)}
|
||||
.subscribe()
|
||||
)
|
||||
}
|
||||
|
||||
private fun registerOsAlarm(alarmCode: AlarmCode, triggerTime: Long): Maybe<AlarmCode> {
|
||||
return Maybe.fromCallable {
|
||||
cancelOsAlarmInternal(alarmCode)
|
||||
val pendingIntent = createPendingIntent(alarmCode, 0)
|
||||
mOsAlarmManager.setAlarmClock(AlarmClockInfo(triggerTime, pendingIntent), pendingIntent)
|
||||
alarmCode
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(alarmCode: AlarmCode): Maybe<AlarmCode> {
|
||||
return if(pm.getAlarms().registered.containsKey(alarmCode)) {
|
||||
cancelOsAlarms(alarmCode)
|
||||
.doOnSuccess {
|
||||
pm.getAlarms().unregister(alarmCode)
|
||||
pm.flushAlarms()
|
||||
}
|
||||
.map { alarmCode }
|
||||
}else{
|
||||
Maybe.just(alarmCode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelOsAlarms(vararg alarmCodes: AlarmCode): Maybe<Int> {
|
||||
return Observable.fromArray(*alarmCodes)
|
||||
.map(this::cancelOsAlarmInternal)
|
||||
.reduce(Integer::sum)
|
||||
}
|
||||
|
||||
private fun cancelOsAlarmInternal(alarmCode: AlarmCode): Int {
|
||||
val old = createPendingIntent(alarmCode, PendingIntent.FLAG_NO_CREATE)
|
||||
return if (old != null) {
|
||||
mOsAlarmManager.cancel(old)
|
||||
old.cancel()
|
||||
aapsLogger.debug("[${alarmCode}] OS Alarm canceled.")
|
||||
1
|
||||
} else {
|
||||
aapsLogger.debug("[${alarmCode}] OS Alarm not canceled, not registered.")
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPendingIntent(alarmCode: AlarmCode, flag: Int): PendingIntent? {
|
||||
val intent = Intent(mContext, OsAlarmReceiver::class.java).setData(getUri(alarmCode))
|
||||
return PendingIntent.getBroadcast(mContext, 1, intent, flag)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.alarm;
|
||||
|
||||
public enum AlarmState {
|
||||
REGISTER,
|
||||
FIRED,
|
||||
HANDLE
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.bindingadapters
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.databinding.BindingAdapter
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.extension.check
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.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))
|
||||
}
|
||||
|
||||
@BindingAdapter("android:text")
|
||||
fun setText(view: TextView, @StringRes resId: Int?) {
|
||||
val text = resId?.let { view.context.getString(it) } ?: ""
|
||||
val oldText = view.text
|
||||
if (text.check(oldText)) {
|
||||
view.text = text
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble;
|
||||
|
||||
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.BleConnectionState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.PatchSelfTestResult;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.ScanList;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.BolusExDuration;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.DeactivationStatus;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.PatchLifecycle;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BasalScheduleSetResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BaseResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusStopResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.ComboBolusStopResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TempBasalScheduleSetResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TemperatureResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.BolusCurrent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.NormalBasal;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchConfig;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchLifecycleEvent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.TempBasal;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
public interface IPatchManager {
|
||||
void init();
|
||||
|
||||
IPreferenceManager getPreferenceManager();
|
||||
|
||||
PatchConfig getPatchConfig();
|
||||
|
||||
boolean isActivated();
|
||||
|
||||
boolean isDeactivated();
|
||||
|
||||
Single<? extends BaseResponse> resumeBasal();
|
||||
|
||||
Observable<PatchLifecycle> observePatchLifeCycle();
|
||||
|
||||
Observable<PatchState> observePatchState();
|
||||
|
||||
BleConnectionState getPatchConnectionState();
|
||||
|
||||
void connect();
|
||||
|
||||
void disconnect();
|
||||
|
||||
PatchState getPatchState();
|
||||
|
||||
void updatePatchState(PatchState state);
|
||||
|
||||
BolusCurrent getBolusCurrent();
|
||||
|
||||
Single<DeactivationStatus> deactivate(long timeout, boolean force);
|
||||
|
||||
Observable<BleConnectionState> observePatchConnectionState();
|
||||
|
||||
Observable<BolusCurrent> observeBolusCurrent();
|
||||
|
||||
void setConnection();
|
||||
|
||||
Single<BolusStopResponse> stopNowBolus();
|
||||
|
||||
Single<BolusStopResponse> stopExtBolus();
|
||||
|
||||
Single<ComboBolusStopResponse> stopComboBolus();
|
||||
|
||||
Single<? extends BolusResponse> startQuickBolus(float nowDoseU, float exDoseU, BolusExDuration exDuration);
|
||||
|
||||
Single<? extends BolusResponse> startCalculatorBolus(DetailedBolusInfo detailedBolusInfo);
|
||||
|
||||
|
||||
Single<PatchBooleanResponse> infoReminderSet(boolean infoReminder);
|
||||
|
||||
Single<PatchBooleanResponse> setLowReservoir(int doseUnit, int hours);
|
||||
|
||||
Single<PatchState> updateConnection();
|
||||
|
||||
long getPatchExpiredTime();
|
||||
|
||||
Single<BasalScheduleSetResponse> startBasal(NormalBasal basal);
|
||||
|
||||
void updatePatchLifeCycle(PatchLifecycleEvent event);
|
||||
|
||||
Single<Boolean> startBond(String mac);
|
||||
|
||||
Single<Boolean> getPatchInfo(long timeout);
|
||||
|
||||
Single<PatchSelfTestResult> selfTest(long timeout);
|
||||
|
||||
Observable<Long> startPriming(long timeout, long count);
|
||||
|
||||
Single<Boolean> checkNeedleSensing(long timeout);
|
||||
|
||||
Single<Boolean> patchActivation(long timeout);
|
||||
|
||||
Single<PatchBooleanResponse> stopAeBeep(int aeCode);
|
||||
|
||||
Single<TempBasalScheduleSetResponse> startTempBasal(TempBasal tempBasal);
|
||||
|
||||
Single<? extends BaseResponse> pauseBasal(float pauseDurationHour);
|
||||
|
||||
Single<ScanList> scan(long timeout);
|
||||
|
||||
Single<PatchBooleanResponse> stopTempBasal();
|
||||
|
||||
Single<TemperatureResponse> getTemperature();
|
||||
|
||||
void addBolusToHistory(DetailedBolusInfo originalDetailedBolusInfo);
|
||||
|
||||
void changeBuzzerSetting();
|
||||
|
||||
void changeReminderSetting();
|
||||
|
||||
void checkActivationProcess();
|
||||
}
|
|
@ -0,0 +1,443 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
import info.nightscout.androidaps.events.EventCustomActionsChanged;
|
||||
import info.nightscout.androidaps.events.EventPumpStatusChanged;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin;
|
||||
import info.nightscout.androidaps.interfaces.CommandQueue;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.interfaces.PumpSync;
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.R;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.RxAction;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.IAlarmRegistry;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.BolusExDuration;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.DeactivationStatus;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.PatchLifecycle;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.SettingKeys;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BasalScheduleSetResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BaseResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusStopResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.ComboBolusStopResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TempBasalScheduleSetResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TemperatureResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.BleConnectionState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.IPatchScanner;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.PatchScanner;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.PatchSelfTestResult;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.ScanList;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.event.EventPatchActivationNotComplete;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.DialogHelperActivity;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.BolusCurrent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.NormalBasal;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchConfig;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchLifecycleEvent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.TempBasal;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.sharedPreferences.SP;
|
||||
import io.reactivex.rxjava3.core.Maybe;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
@Singleton
|
||||
public class PatchManager implements IPatchManager {
|
||||
|
||||
@Inject PatchManagerImpl patchManager;
|
||||
@Inject IPreferenceManager pm;
|
||||
@Inject ProfileFunction profileFunction;
|
||||
@Inject ActivePlugin activePlugin;
|
||||
@Inject CommandQueue commandQueue;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject ResourceHelper resourceHelper;
|
||||
@Inject RxBus rxBus;
|
||||
@Inject Context context;
|
||||
@Inject SP sp;
|
||||
@Inject PumpSync pumpSync;
|
||||
@Inject DateUtil dateUtil;
|
||||
@Inject RxAction rxAction;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
@Inject IAlarmRegistry alarmRegistry;
|
||||
|
||||
private IPatchScanner patchScanner;
|
||||
private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();
|
||||
private Disposable mConnectingDisposable = null;
|
||||
|
||||
@Inject
|
||||
public PatchManager() {}
|
||||
|
||||
@Inject
|
||||
void onInit() {
|
||||
patchScanner = new PatchScanner(context);
|
||||
|
||||
mCompositeDisposable.add(observePatchConnectionState()
|
||||
.subscribe(bleConnectionState -> {
|
||||
switch (bleConnectionState) {
|
||||
case DISCONNECTED:
|
||||
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED));
|
||||
rxBus.send(new EventRefreshOverview("Eopatch connection state: " + bleConnectionState.name(), true));
|
||||
rxBus.send(new EventCustomActionsChanged());
|
||||
stopObservingConnection();
|
||||
break;
|
||||
|
||||
case CONNECTED:
|
||||
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED));
|
||||
rxBus.send(new EventRefreshOverview("Eopatch connection state: " + bleConnectionState.name(), true));
|
||||
rxBus.send(new EventCustomActionsChanged());
|
||||
stopObservingConnection();
|
||||
break;
|
||||
|
||||
case CONNECTING:
|
||||
mConnectingDisposable = Observable.interval(0, 1, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.takeUntil(n -> getPatchConnectionState().isConnected() || n > 10 * 60)
|
||||
.subscribe(n -> rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, n.intValue())));
|
||||
break;
|
||||
|
||||
default:
|
||||
stopObservingConnection();
|
||||
}
|
||||
})
|
||||
);
|
||||
mCompositeDisposable.add(rxBus
|
||||
.toObservable(EventPatchActivationNotComplete.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribeOn(aapsSchedulers.getMain())
|
||||
.subscribe(eventPatchActivationNotComplete -> {
|
||||
Intent i = new Intent(context, DialogHelperActivity.class);
|
||||
i.putExtra("title", resourceHelper.gs(R.string.patch_activate_reminder_title));
|
||||
i.putExtra("message", resourceHelper.gs(R.string.patch_activate_reminder_desc));
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(i);
|
||||
})
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
setConnection();
|
||||
}
|
||||
|
||||
private void stopObservingConnection(){
|
||||
if(mConnectingDisposable != null) {
|
||||
mConnectingDisposable.dispose();
|
||||
mConnectingDisposable = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPreferenceManager getPreferenceManager() {
|
||||
return pm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PatchConfig getPatchConfig() {
|
||||
return pm.getPatchConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<PatchLifecycle> observePatchLifeCycle() {
|
||||
return pm.observePatchLifeCycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updatePatchLifeCycle(PatchLifecycleEvent event) {
|
||||
pm.updatePatchLifeCycle(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BleConnectionState getPatchConnectionState() {
|
||||
return patchManager.getPatchConnectionState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<BleConnectionState> observePatchConnectionState() {
|
||||
return patchManager.observePatchConnectionState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PatchState getPatchState() {
|
||||
return pm.getPatchState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePatchState(PatchState state) {
|
||||
pm.getPatchState().update(state);
|
||||
pm.flushPatchState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<PatchState> observePatchState() {
|
||||
return pm.observePatchState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatchExpiredTime() {
|
||||
return pm.getPatchConfig().getPatchExpiredTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BolusCurrent getBolusCurrent() {
|
||||
return pm.getBolusCurrent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<BolusCurrent> observeBolusCurrent() {
|
||||
return pm.observeBolusCurrent();
|
||||
}
|
||||
|
||||
|
||||
public void connect() {
|
||||
// Nothing (Auto Connect mode)
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
// Nothing (Auto Connect mode)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConnection() {
|
||||
if(pm.getPatchConfig().hasMacAddress()){
|
||||
patchManager.updateMacAddress(pm.getPatchConfig().getMacAddress(), false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActivated() {
|
||||
return pm.getPatchConfig().isActivated();
|
||||
}
|
||||
|
||||
public boolean isDeactivated() {
|
||||
return pm.getPatchConfig().isDeactivated();
|
||||
}
|
||||
|
||||
public Single<Boolean> startBond(String mac) {
|
||||
return patchManager.startBond(mac);
|
||||
}
|
||||
|
||||
public Single<Boolean> getPatchInfo(long timeout) {
|
||||
return patchManager.getPatchInfo(timeout);
|
||||
}
|
||||
|
||||
public Single<PatchSelfTestResult> selfTest(long timeout) {
|
||||
return patchManager.selfTest(timeout);
|
||||
}
|
||||
|
||||
public Single<TemperatureResponse> getTemperature() {
|
||||
return patchManager.getTemperature();
|
||||
}
|
||||
|
||||
public Observable<Long> startPriming(long timeout, long count) {
|
||||
return patchManager.startPriming(timeout, count);
|
||||
}
|
||||
|
||||
public Single<Boolean> checkNeedleSensing(long timeout) {
|
||||
return patchManager.checkNeedleSensing(timeout);
|
||||
}
|
||||
|
||||
public Single<Boolean> patchActivation(long timeout) {
|
||||
return patchManager.patchActivation(timeout)
|
||||
.doOnSuccess(success -> {
|
||||
// if (success) {
|
||||
// pumpSync.insertTherapyEventIfNewWithTimestamp(
|
||||
// getPatchConfig().getPatchWakeupTimestamp(),
|
||||
// DetailedBolusInfo.EventType.CANNULA_CHANGE,
|
||||
// null,
|
||||
// null,
|
||||
// PumpType.EOFLOW_EOPATCH2,
|
||||
// getPatchConfig().getPatchSerialNumber()
|
||||
// );
|
||||
// pumpSync.insertTherapyEventIfNewWithTimestamp(
|
||||
// getPatchConfig().getPatchWakeupTimestamp(),
|
||||
// DetailedBolusInfo.EventType.INSULIN_CHANGE,
|
||||
// null,
|
||||
// null,
|
||||
// PumpType.EOFLOW_EOPATCH2,
|
||||
// getPatchConfig().getPatchSerialNumber()
|
||||
// );
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
public Single<BasalScheduleSetResponse> startBasal(NormalBasal basal) {
|
||||
return patchManager.startBasal(basal);
|
||||
}
|
||||
|
||||
public Single<? extends BaseResponse> resumeBasal() {
|
||||
return patchManager.resumeBasal();
|
||||
}
|
||||
|
||||
|
||||
public Single<? extends BaseResponse> pauseBasal(float pauseDurationHour) {
|
||||
return patchManager.pauseBasal(pauseDurationHour);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// IPatchManager interface [TEMP BASAL]
|
||||
//==============================================================================================
|
||||
|
||||
public Single<TempBasalScheduleSetResponse> startTempBasal(TempBasal tempBasal) {
|
||||
return patchManager.startTempBasal(tempBasal);
|
||||
}
|
||||
|
||||
// 템프베이젤 주입 정지
|
||||
// 템프베이젤이 정지되면 자동으로 노멀베이젤이 활성화된다
|
||||
// 외부에서 호출된다. 즉 명시적으로 tempBasal 정지. 이 때는 normalBasal resume 은 PatchState 보고 처리.
|
||||
|
||||
public Single<PatchBooleanResponse> stopTempBasal() {
|
||||
return patchManager.stopTempBasal();
|
||||
}
|
||||
|
||||
|
||||
public Single<? extends BolusResponse> startQuickBolus(float nowDoseU, float exDoseU,
|
||||
BolusExDuration exDuration) {
|
||||
return patchManager.startQuickBolus(nowDoseU, exDoseU, exDuration);
|
||||
}
|
||||
|
||||
|
||||
public Single<? extends BolusResponse> startCalculatorBolus(DetailedBolusInfo detailedBolusInfo) {
|
||||
return patchManager.startCalculatorBolus(detailedBolusInfo);
|
||||
}
|
||||
|
||||
|
||||
public Single<BolusStopResponse> stopNowBolus() {
|
||||
return patchManager.stopNowBolus();
|
||||
}
|
||||
|
||||
|
||||
public Single<BolusStopResponse> stopExtBolus() {
|
||||
return patchManager.stopExtBolus();
|
||||
}
|
||||
|
||||
|
||||
public Single<ComboBolusStopResponse> stopComboBolus(){
|
||||
return patchManager.stopComboBolus();
|
||||
}
|
||||
|
||||
public Single<DeactivationStatus> deactivate(long timeout, boolean force) {
|
||||
return patchManager.deactivate(timeout, force);
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> infoReminderSet(boolean infoReminder) {
|
||||
return patchManager.infoReminderSet(infoReminder);
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> setLowReservoir(int doseUnit, int hours) {
|
||||
return patchManager.setLowReservoir(doseUnit, hours);
|
||||
}
|
||||
|
||||
public Single<PatchState> updateConnection() {
|
||||
return patchManager.updateConnection();
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> stopAeBeep(int aeCode) {
|
||||
return patchManager.stopAeBeep(aeCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<ScanList> scan(long timeout) {
|
||||
patchManager.updateMacAddress("", false);
|
||||
pm.getPatchConfig().setMacAddress("");
|
||||
return patchScanner.scan(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBolusToHistory(DetailedBolusInfo originalDetailedBolusInfo) {
|
||||
DetailedBolusInfo detailedBolusInfo = originalDetailedBolusInfo.copy();
|
||||
|
||||
if(detailedBolusInfo.insulin > 0) {
|
||||
pumpSync.syncBolusWithPumpId(
|
||||
detailedBolusInfo.timestamp,
|
||||
detailedBolusInfo.insulin,
|
||||
detailedBolusInfo.getBolusType(),
|
||||
dateUtil.now(),
|
||||
PumpType.EOFLOW_EOPATCH2,
|
||||
patchManager.pm.getPatchSerial()
|
||||
);
|
||||
}
|
||||
if (detailedBolusInfo.carbs > 0) {
|
||||
pumpSync.syncCarbsWithTimestamp(
|
||||
detailedBolusInfo.getCarbsTimestamp() != null ? detailedBolusInfo.getCarbsTimestamp() : detailedBolusInfo.timestamp,
|
||||
detailedBolusInfo.carbs,
|
||||
null,
|
||||
PumpType.USER,
|
||||
patchManager.pm.getPatchSerial()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeBuzzerSetting() {
|
||||
boolean buzzer = sp.getBoolean(SettingKeys.Companion.getBUZZER_REMINDERS(), false);
|
||||
if(pm.getPatchConfig().getInfoReminder() != buzzer) {
|
||||
if (isActivated()) {
|
||||
mCompositeDisposable.add(infoReminderSet(buzzer)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(patchBooleanResponse -> {
|
||||
pm.getPatchConfig().setInfoReminder(buzzer);
|
||||
pm.flushPatchConfig();
|
||||
}));
|
||||
} else {
|
||||
pm.getPatchConfig().setInfoReminder(buzzer);
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeReminderSetting() {
|
||||
int doseUnit = sp.getInt(SettingKeys.Companion.getLOW_RESERVOIR_REMINDERS(), 0);
|
||||
int hours = sp.getInt(SettingKeys.Companion.getEXPIRATION_REMINDERS(), 0);
|
||||
PatchConfig pc = pm.getPatchConfig();
|
||||
if(pc.getLowReservoirAlertAmount() != doseUnit || pc.getPatchExpireAlertTime() != hours) {
|
||||
if (isActivated()) {
|
||||
mCompositeDisposable.add(setLowReservoir(doseUnit, hours)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.doOnSubscribe(disposable -> {
|
||||
if(pc.getPatchExpireAlertTime() != hours){
|
||||
Maybe.just(AlarmCode.B000)
|
||||
.flatMap(alarmCode -> alarmRegistry.remove(alarmCode))
|
||||
.flatMap(alarmCode -> alarmRegistry.add(alarmCode, (pc.getExpireTimestamp() - System.currentTimeMillis() - TimeUnit.HOURS.toMillis(hours)), false))
|
||||
.subscribe();
|
||||
}
|
||||
})
|
||||
.subscribe(patchBooleanResponse -> {
|
||||
pc.setLowReservoirAlertAmount(doseUnit);
|
||||
pc.setPatchExpireAlertTime(hours);
|
||||
pm.flushPatchConfig();
|
||||
}));
|
||||
} else {
|
||||
pc.setLowReservoirAlertAmount(doseUnit);
|
||||
pc.setPatchExpireAlertTime(hours);
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkActivationProcess(){
|
||||
if(getPatchConfig().getLifecycleEvent().isSubStepRunning()
|
||||
&& !pm.getAlarms().isOccurring(AlarmCode.A005)
|
||||
&& !pm.getAlarms().isOccurring(AlarmCode.A020)) {
|
||||
rxAction.runOnMainThread(() -> rxBus.send(new EventPatchActivationNotComplete()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,737 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble;
|
||||
|
||||
import static android.content.Intent.ACTION_DATE_CHANGED;
|
||||
import static android.content.Intent.ACTION_TIMEZONE_CHANGED;
|
||||
import static android.content.Intent.ACTION_TIME_CHANGED;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.security.spec.ECPoint;
|
||||
import java.security.spec.ECPublicKeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.crypto.KeyAgreement;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
import info.nightscout.androidaps.interfaces.PumpSync;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.EoPatchRxBus;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.ActivateTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.DeactivateTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.GetPatchInfoTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.InfoReminderTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.NeedleSensingTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.PauseBasalTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.PrimingTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.ResumeBasalTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.SelfTestTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.SetLowReservoirTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StartBondTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StartCalcBolusTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StartNormalBasalTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StartQuickBolusTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StartTempBasalTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StopComboBolusTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StopExtBolusTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StopNowBolusTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.StopTempBasalTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.SyncBasalHistoryTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.TaskBase;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.TaskFunc;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.UpdateConnectionTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.BolusExDuration;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.DeactivationStatus;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.SettingKeys;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.Patch;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BuzzerStop;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetTemperature;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.PublicKeySend;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.SequenceGet;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.StopAeBeep;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.code.BolusType;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.noti.AlarmNotification;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.noti.BaseNotification;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.noti.InfoNotification;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BasalScheduleSetResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BaseResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusStopResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.ComboBolusStopResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.KeyResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TempBasalScheduleSetResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TemperatureResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.BleConnectionState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.IBleDevice;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.PatchSelfTestResult;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.event.EventEoPatchAlarm;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.receiver.RxBroadcastReceiver;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.BolusCurrent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.NormalBasal;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchConfig;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.TempBasal;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.shared.sharedPreferences.SP;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Scheduler;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import io.reactivex.rxjava3.functions.Consumer;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
@Singleton
|
||||
public class PatchManagerImpl{
|
||||
@Inject IPreferenceManager pm;
|
||||
@Inject Context context;
|
||||
@Inject SP sp;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
@Inject PumpSync pumpSync;
|
||||
|
||||
@Inject StartBondTask START_BOND;
|
||||
@Inject GetPatchInfoTask GET_PATCH_INFO;
|
||||
@Inject SelfTestTask SELF_TEST;
|
||||
@Inject PrimingTask START_PRIMING;
|
||||
@Inject NeedleSensingTask START_NEEDLE_CHECK;
|
||||
|
||||
IBleDevice patch;
|
||||
|
||||
private final CompositeDisposable compositeDisposable;
|
||||
|
||||
private static final long DEFAULT_API_TIME_OUT = 10; // SECONDS
|
||||
|
||||
private final BuzzerStop BUZZER_STOP;
|
||||
private final GetTemperature TEMPERATURE_GET;
|
||||
private final StopAeBeep ALARM_ALERT_ERROR_BEEP_STOP;
|
||||
private final PublicKeySend PUBLIC_KEY_SET;
|
||||
private final SequenceGet SEQUENCE_GET;
|
||||
|
||||
@Inject
|
||||
public PatchManagerImpl() {
|
||||
compositeDisposable = new CompositeDisposable();
|
||||
|
||||
BUZZER_STOP = new BuzzerStop();
|
||||
TEMPERATURE_GET = new GetTemperature();
|
||||
ALARM_ALERT_ERROR_BEEP_STOP = new StopAeBeep();
|
||||
PUBLIC_KEY_SET = new PublicKeySend();
|
||||
SEQUENCE_GET = new SequenceGet();
|
||||
}
|
||||
|
||||
@Inject
|
||||
void onInit() {
|
||||
patch = Patch.getInstance();
|
||||
patch.init(context);
|
||||
patch.setSeq(pm.getPatchConfig().getSeq15());
|
||||
|
||||
IntentFilter filter = new IntentFilter(ACTION_TIME_CHANGED);
|
||||
filter.addAction(ACTION_DATE_CHANGED);
|
||||
filter.addAction(ACTION_TIMEZONE_CHANGED);
|
||||
|
||||
Observable<Intent> dateTimeChanged = RxBroadcastReceiver.Companion.create(context, filter);
|
||||
|
||||
compositeDisposable.add(
|
||||
Observable.combineLatest(patch.observeConnected(), pm.observePatchLifeCycle(),
|
||||
(connected, lifeCycle) -> (connected && lifeCycle.isActivated()))
|
||||
.subscribeOn(aapsSchedulers.getIo())
|
||||
.filter(ok -> ok)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.doOnNext(v -> TaskBase.enqueue(TaskFunc.UPDATE_CONNECTION))
|
||||
.retry()
|
||||
.subscribe());
|
||||
|
||||
compositeDisposable.add(
|
||||
Observable.combineLatest(patch.observeConnected(),
|
||||
pm.observePatchLifeCycle().distinctUntilChanged(),
|
||||
dateTimeChanged.startWith(Observable.just(new Intent())),
|
||||
(connected, lifeCycle, value) -> (connected && lifeCycle.isActivated()))
|
||||
.subscribeOn(aapsSchedulers.getIo())
|
||||
.doOnNext(v -> aapsLogger.debug(LTag.PUMP,"Has the date or time changed? "+v))
|
||||
.filter(ok -> ok)
|
||||
.doOnNext(v -> TaskBase.enqueue(TaskFunc.SET_GLOBAL_TIME))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMP, "Failed to set EOPatch time."))
|
||||
.retry()
|
||||
.subscribe());
|
||||
|
||||
compositeDisposable.add(
|
||||
patch.observeConnected()
|
||||
.doOnNext(this::onPatchConnected)
|
||||
.subscribe());
|
||||
|
||||
compositeDisposable.add(
|
||||
pm.getPatchConfig().observe().doOnNext(config -> {
|
||||
byte[] newKey = config.getSharedKey();
|
||||
patch.updateEncryptionParam(newKey);
|
||||
}).subscribe()
|
||||
);
|
||||
|
||||
compositeDisposable.add(
|
||||
EoPatchRxBus.INSTANCE.listen(EventEoPatchAlarm.class)
|
||||
.filter(EventEoPatchAlarm::isFirst)
|
||||
.filter(it -> !pm.getPatchConfig().isDeactivated())
|
||||
.filter(it -> patch.getConnectionState().isConnected())
|
||||
.concatMapIterable(EventEoPatchAlarm::getAlarmCodes)
|
||||
.filter(AlarmCode::isPatchOccurrenceAlert)
|
||||
.flatMap(it -> stopAeBeep(it.getAeCode()).toObservable())
|
||||
.subscribe()
|
||||
);
|
||||
|
||||
compositeDisposable.add(
|
||||
EoPatchRxBus.INSTANCE.listen(EventEoPatchAlarm.class)
|
||||
.filter(EventEoPatchAlarm::isFirst)
|
||||
.filter(it -> !pm.getPatchConfig().isDeactivated())
|
||||
.filter(it -> patch.getConnectionState().isConnected())
|
||||
.concatMapIterable(EventEoPatchAlarm::getAlarmCodes)
|
||||
.filter(AlarmCode::isPatchOccurrenceAlarm)
|
||||
.flatMap(it -> pauseBasalImpl(0.0f, System.currentTimeMillis(), it).toObservable())
|
||||
.subscribe()
|
||||
);
|
||||
|
||||
|
||||
monitorPatchNotification();
|
||||
onConnectedUpdateSequence();
|
||||
}
|
||||
|
||||
private void onPatchConnected(boolean connected) {
|
||||
boolean activated = pm.getPatchConfig().isActivated();
|
||||
boolean useEncryption = pm.getPatchConfig().getSharedKey() != null;
|
||||
int doseUnit = sp.getInt(SettingKeys.Companion.getLOW_RESERVOIR_REMINDERS(), 0);
|
||||
int hours = sp.getInt(SettingKeys.Companion.getEXPIRATION_REMINDERS(), 0);
|
||||
boolean buzzer = sp.getBoolean(SettingKeys.Companion.getBUZZER_REMINDERS(), false);
|
||||
PatchConfig pc = pm.getPatchConfig();
|
||||
|
||||
if (connected && activated && useEncryption) {
|
||||
compositeDisposable.add(
|
||||
SEQUENCE_GET.get()
|
||||
.map(KeyResponse::getSequence)
|
||||
.doOnSuccess(sequence -> {
|
||||
if (sequence >= 0) {
|
||||
saveSequence(sequence);
|
||||
}
|
||||
})
|
||||
.flatMap(integer -> {
|
||||
if(pc.getLowReservoirAlertAmount() != doseUnit || pc.getPatchExpireAlertTime() != hours) {
|
||||
return setLowReservoir(doseUnit, hours)
|
||||
.doOnSuccess(patchBooleanResponse -> {
|
||||
pc.setLowReservoirAlertAmount(doseUnit);
|
||||
pc.setPatchExpireAlertTime(hours);
|
||||
pm.flushPatchConfig();
|
||||
}).map(patchBooleanResponse -> true);
|
||||
}
|
||||
return Single.just(true);
|
||||
})
|
||||
.flatMap(ret -> {
|
||||
if(pc.getInfoReminder() != buzzer) {
|
||||
return infoReminderSet(buzzer)
|
||||
.doOnSuccess(patchBooleanResponse -> {
|
||||
pc.setInfoReminder(buzzer);
|
||||
pm.flushPatchConfig();
|
||||
}).map(patchBooleanResponse -> true);
|
||||
}
|
||||
return Single.just(true);
|
||||
})
|
||||
.subscribe());
|
||||
}
|
||||
|
||||
if(!connected && activated){
|
||||
pm.getPatchConfig().updatetDisconnectedTime();
|
||||
}
|
||||
}
|
||||
|
||||
private void monitorPatchNotification() {
|
||||
compositeDisposable.addAll(
|
||||
patch.observeAlarmNotification()
|
||||
.subscribe(
|
||||
this::onAlarmNotification,
|
||||
throwable -> aapsLogger.error(LTag.PUMP, throwable.getMessage() != null ?
|
||||
throwable.getMessage() : "AlarmNotification observation error")
|
||||
),
|
||||
patch.observeInfoNotification()
|
||||
.filter(state -> pm.getPatchConfig().isActivated())
|
||||
.subscribe(
|
||||
this::onInfoNotification,
|
||||
throwable -> aapsLogger.error(LTag.PUMP, throwable.getMessage() != null ?
|
||||
throwable.getMessage() : "InfoNotification observation error")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private void onConnectedUpdateSequence() {
|
||||
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// preference database update helper
|
||||
//==============================================================================================
|
||||
|
||||
// synchronized lock
|
||||
private final Object lock = new Object();
|
||||
|
||||
private void updatePatchConfig(Consumer<PatchConfig> consumer, boolean needSave) throws Throwable {
|
||||
synchronized (lock) {
|
||||
consumer.accept(pm.getPatchConfig());
|
||||
if (needSave) {
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void updateBasal() {
|
||||
|
||||
NormalBasal normalBasal = pm.getNormalBasalManager().getNormalBasal();
|
||||
|
||||
if(normalBasal.updateNormalBasalIndex()) {
|
||||
pm.flushNormalBasalManager();
|
||||
}
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* getPatchConnection() 을 사용해야 한다.
|
||||
* 아직 Life Cycle 이 Activated 가 아님.
|
||||
*
|
||||
* Activation Process task #1 Get Patch Information from Patch
|
||||
* Fragment: fragment_patch_connect_new
|
||||
*/
|
||||
|
||||
public Single<Boolean> startBond(String mac) {
|
||||
return START_BOND.start(mac);
|
||||
}
|
||||
|
||||
public Single<Boolean> getPatchInfo(long timeout) {
|
||||
return GET_PATCH_INFO.get().timeout(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Activation Process task #2 Check Patch is O.K
|
||||
* Fragment: fragment_patch_connect_new
|
||||
*/
|
||||
public Single<PatchSelfTestResult> selfTest(long timeout) {
|
||||
return SELF_TEST.start().timeout(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activation Process task #3 PRIMING
|
||||
* Fragment: fragment_patch_priming
|
||||
*/
|
||||
|
||||
public Single<TemperatureResponse> getTemperature() {
|
||||
return TEMPERATURE_GET.get()
|
||||
.timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public Observable<Long> startPriming(long timeout, long count) {
|
||||
return START_PRIMING.start(count)
|
||||
.timeout(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activation Process task #4 NEEDLE SENSING
|
||||
* Fragment: fragment_patch_rotate_knob
|
||||
*/
|
||||
public Single<Boolean> checkNeedleSensing(long timeout) {
|
||||
return START_NEEDLE_CHECK.start()
|
||||
.timeout(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activation Process task #5 Activation Secure Key, Basal writing
|
||||
* Fragment: fragment_patch_check_patch
|
||||
*/
|
||||
@Inject
|
||||
ActivateTask ACTIVATE;
|
||||
|
||||
public Single<Boolean> patchActivation(long timeout) {
|
||||
|
||||
return ACTIVATE.start().timeout(timeout, TimeUnit.MILLISECONDS)
|
||||
.flatMap(success -> sharedKey())
|
||||
.flatMap(success -> getSequence())
|
||||
.doOnSuccess(success -> {
|
||||
if (success) {
|
||||
TaskBase.enqueue(TaskFunc.LOW_RESERVOIR);
|
||||
TaskBase.enqueue(TaskFunc.INFO_REMINDER);
|
||||
pumpSync.connectNewPump(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================================
|
||||
// IPatchManager interface [NORMAL BASAL]
|
||||
//==============================================================================================
|
||||
|
||||
@Inject
|
||||
StartNormalBasalTask startNormalBasalTask;
|
||||
|
||||
public Single<BasalScheduleSetResponse> startBasal(NormalBasal basal) {
|
||||
|
||||
return startNormalBasalTask.start(basal)
|
||||
.timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Inject
|
||||
ResumeBasalTask resumeBasalTask;
|
||||
|
||||
public Single<? extends BaseResponse> resumeBasal() {
|
||||
return resumeBasalTask.resume()
|
||||
.timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public Single<? extends BaseResponse> pauseBasal(float pauseDurationHour) {
|
||||
return pauseBasalImpl(pauseDurationHour, 0, null)
|
||||
.observeOn(SS)
|
||||
.timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// IPatchManager implementation [NORMAL BASAL]
|
||||
//==============================================================================================
|
||||
|
||||
@Inject
|
||||
PauseBasalTask pauseBasalTask;
|
||||
|
||||
private Single<? extends BaseResponse> pauseBasalImpl(float pauseDurationHour, long alarmOccurredTime, @Nullable AlarmCode alarmCode) {
|
||||
return pauseBasalTask.pause(pauseDurationHour, alarmOccurredTime, alarmCode);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// IPatchManager interface [TEMP BASAL]
|
||||
//==============================================================================================
|
||||
|
||||
@Inject
|
||||
StartTempBasalTask startTempBasalTask;
|
||||
|
||||
public Single<TempBasalScheduleSetResponse> startTempBasal(TempBasal tempBasal) {
|
||||
return startTempBasalTask.start(tempBasal).timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// 템프베이젤 주입 정지
|
||||
// 템프베이젤이 정지되면 자동으로 노멀베이젤이 활성화된다
|
||||
// 외부에서 호출된다. 즉 명시적으로 tempBasal 정지. 이 때는 normalBasal resume 은 PatchState 보고 처리.
|
||||
|
||||
@Inject
|
||||
StopTempBasalTask stopTempBasalTask;
|
||||
|
||||
public Single<PatchBooleanResponse> stopTempBasal() {
|
||||
return stopTempBasalTask.stop().timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Inject
|
||||
StartQuickBolusTask startQuickBolusTask;
|
||||
|
||||
@Inject
|
||||
StartCalcBolusTask startCalcBolusTask;
|
||||
|
||||
@Inject
|
||||
StopComboBolusTask stopComboBolusTask;
|
||||
|
||||
@Inject
|
||||
StopNowBolusTask stopNowBolusTask;
|
||||
|
||||
@Inject
|
||||
StopExtBolusTask stopExtBolusTask;
|
||||
|
||||
|
||||
public Single<? extends BolusResponse> startQuickBolus(float nowDoseU, float exDoseU,
|
||||
BolusExDuration exDuration) {
|
||||
return startQuickBolusTask.start(nowDoseU, exDoseU, exDuration)
|
||||
.timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public Single<? extends BolusResponse> startCalculatorBolus(DetailedBolusInfo detailedBolusInfo) {
|
||||
return startCalcBolusTask.start(detailedBolusInfo)
|
||||
.timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public Single<BolusStopResponse> stopNowBolus() {
|
||||
return stopNowBolusTask.stop().timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public Single<BolusStopResponse> stopExtBolus() {
|
||||
return stopExtBolusTask.stop().timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public Single<ComboBolusStopResponse> stopComboBolus(){
|
||||
return stopComboBolusTask.stop().timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// private Single<? extends BaseResponse> stopNowAndExtBolus() {
|
||||
//
|
||||
// boolean nowActive = pm.getPatchState().isNowBolusActive();
|
||||
// boolean extActive = pm.getPatchState().isExtBolusActive();
|
||||
//
|
||||
// if (nowActive && extActive) {
|
||||
// return stopComboBolus();
|
||||
// } else if (nowActive) {
|
||||
// return stopNowBolus();
|
||||
// } else if (extActive) {
|
||||
// return stopExtBolus();
|
||||
// }
|
||||
//
|
||||
// return Single.just(new PatchBooleanResponse(true));
|
||||
// }
|
||||
|
||||
//==============================================================================================
|
||||
// IPatchManager implementation [BOLUS]
|
||||
//==============================================================================================
|
||||
|
||||
public void readBolusStatusFromNotification(InfoNotification infoNotification) {
|
||||
if (infoNotification.isBolusRegAct()) {
|
||||
BolusCurrent bolusCurrent = pm.getBolusCurrent();
|
||||
|
||||
Arrays.asList(BolusType.NOW, BolusType.EXT).forEach(type -> {
|
||||
if (infoNotification.isBolusRegAct(type)) { // 완료되었어도 업데이트 필요.
|
||||
int injectedPumpCount = infoNotification.getInjected(type);
|
||||
int remainPumpCount = infoNotification.getRemain(type);
|
||||
bolusCurrent.updateBolusFromPatch(type, injectedPumpCount, remainPumpCount);
|
||||
}
|
||||
});
|
||||
pm.flushBolusCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Inject
|
||||
DeactivateTask deactivateTask;
|
||||
// Patch Activation Tasks
|
||||
public Single<DeactivationStatus> deactivate(long timeout, boolean force) {
|
||||
return deactivateTask.run(force, timeout);
|
||||
}
|
||||
|
||||
@Inject
|
||||
InfoReminderTask infoReminderTask;
|
||||
|
||||
public Single<PatchBooleanResponse> infoReminderSet(boolean infoReminder) {
|
||||
return infoReminderTask.set(infoReminder).timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Inject
|
||||
SetLowReservoirTask setLowReservoirTask;
|
||||
public Single<PatchBooleanResponse> setLowReservoir(int doseUnit, int hours) {
|
||||
return setLowReservoirTask.set(doseUnit, hours).timeout(DEFAULT_API_TIME_OUT, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Inject
|
||||
UpdateConnectionTask updateConnectionTask;
|
||||
public Single<PatchState> updateConnection() {
|
||||
return updateConnectionTask.update();
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> stopAeBeep(int aeCode) {
|
||||
return ALARM_ALERT_ERROR_BEEP_STOP.stop(aeCode);
|
||||
}
|
||||
|
||||
synchronized void fetchPatchState() {
|
||||
updateConnectionTask.enqueue();
|
||||
}
|
||||
|
||||
@Inject
|
||||
PatchStateManager patchStateManager;
|
||||
|
||||
@Inject
|
||||
SyncBasalHistoryTask syncBasalHistoryTask;
|
||||
|
||||
void onAlarmNotification(AlarmNotification notification) throws Throwable {
|
||||
patchStateManager.updatePatchState(PatchState.create(notification.patchState, System.currentTimeMillis()));
|
||||
|
||||
if (pm.getPatchConfig().isActivated()) {
|
||||
if(!patch.isSeqReady()){
|
||||
getSequence().subscribe();
|
||||
}
|
||||
updateBasal();
|
||||
updateInjected(notification, true);
|
||||
fetchPatchState();
|
||||
}
|
||||
}
|
||||
|
||||
private void onInfoNotification(InfoNotification notification) throws Throwable {
|
||||
readBolusStatusFromNotification(notification);
|
||||
updateInjected(notification, false);
|
||||
if (notification.isBolusDone()) {
|
||||
fetchPatchState();
|
||||
}
|
||||
}
|
||||
|
||||
void updateInjected(BaseNotification notification, boolean needSave) throws Throwable {
|
||||
updatePatchConfig(patchConfig -> {
|
||||
patchConfig.setInjectCount(notification.getTotalInjected());
|
||||
patchConfig.setStandardBolusInjectCount(notification.getSB_CNT());
|
||||
patchConfig.setExtendedBolusInjectCount(notification.getEB_CNT());
|
||||
patchConfig.setBasalInjectCount(notification.getBasal_CNT());
|
||||
}, needSave);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// Security
|
||||
//==============================================================================================
|
||||
private static final String SECP256R1 = "secp256r1";
|
||||
private static final String EC = "EC";
|
||||
private static final String ECDH = "ECDH";
|
||||
|
||||
public Single<Boolean> sharedKey() {
|
||||
return genKeyPair().flatMap(keyPair -> ECPublicToRawBytes(keyPair)
|
||||
.flatMap(bytes -> PUBLIC_KEY_SET.send(bytes)
|
||||
.map(KeyResponse::getPublicKey)
|
||||
.map(bytes2 -> rawToEncodedECPublicKey(SECP256R1, bytes2))
|
||||
.map(publicKey -> generateSharedSecret(keyPair.getPrivate(), publicKey))
|
||||
.doOnSuccess(this::saveShared).map(v2 -> true)))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMP, "sharedKey error"));
|
||||
}
|
||||
|
||||
public Single<Boolean> getSequence() {
|
||||
return SEQUENCE_GET.get()
|
||||
.map(KeyResponse::getSequence)
|
||||
.doOnSuccess(sequence -> {
|
||||
if (sequence >= 0) {
|
||||
saveSequence(sequence);
|
||||
}
|
||||
})
|
||||
.flatMap(v -> Single.just(true));
|
||||
}
|
||||
|
||||
private void saveShared(byte[] v) {
|
||||
pm.getPatchConfig().setSharedKey(v);
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
|
||||
private void saveSequence(int sequence) {
|
||||
patch.setSeq(sequence);
|
||||
pm.getPatchConfig().setSeq15(sequence);
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
|
||||
public Single<KeyPair> genKeyPair() {
|
||||
return Single.fromCallable(() -> {
|
||||
ECGenParameterSpec ecSpec_named = new ECGenParameterSpec(SECP256R1);
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance(EC);
|
||||
kpg.initialize(ecSpec_named);
|
||||
return kpg.generateKeyPair();
|
||||
});
|
||||
}
|
||||
|
||||
public Single<byte[]> ECPublicToRawBytes(KeyPair keyPair) {
|
||||
return Single.just(keyPair.getPublic()).cast(ECPublicKey.class)
|
||||
.map(PatchManagerImpl::encodeECPublicKey);
|
||||
}
|
||||
|
||||
private static byte[] encodeECPublicKey(ECPublicKey pubKey) {
|
||||
int keyLengthBytes = pubKey.getParams().getOrder().bitLength()
|
||||
/ Byte.SIZE;
|
||||
byte[] publicKeyEncoded = new byte[2 * keyLengthBytes];
|
||||
|
||||
int offset = 0;
|
||||
|
||||
BigInteger x = pubKey.getW().getAffineX();
|
||||
byte[] xba = x.toByteArray();
|
||||
if (xba.length > keyLengthBytes + 1 || xba.length == keyLengthBytes + 1
|
||||
&& xba[0] != 0) {
|
||||
throw new IllegalStateException(
|
||||
"X coordinate of EC public key has wrong size");
|
||||
}
|
||||
|
||||
if (xba.length == keyLengthBytes + 1) {
|
||||
System.arraycopy(xba, 1, publicKeyEncoded, offset, keyLengthBytes);
|
||||
} else {
|
||||
System.arraycopy(xba, 0, publicKeyEncoded, offset + keyLengthBytes
|
||||
- xba.length, xba.length);
|
||||
}
|
||||
offset += keyLengthBytes;
|
||||
|
||||
BigInteger y = pubKey.getW().getAffineY();
|
||||
byte[] yba = y.toByteArray();
|
||||
if (yba.length > keyLengthBytes + 1 || yba.length == keyLengthBytes + 1
|
||||
&& yba[0] != 0) {
|
||||
throw new IllegalStateException(
|
||||
"Y coordinate of EC public key has wrong size");
|
||||
}
|
||||
|
||||
if (yba.length == keyLengthBytes + 1) {
|
||||
System.arraycopy(yba, 1, publicKeyEncoded, offset, keyLengthBytes);
|
||||
} else {
|
||||
System.arraycopy(yba, 0, publicKeyEncoded, offset + keyLengthBytes
|
||||
- yba.length, yba.length);
|
||||
}
|
||||
|
||||
return publicKeyEncoded;
|
||||
}
|
||||
|
||||
public static ECPublicKey rawToEncodedECPublicKey(String curveName, byte[] rawBytes) throws
|
||||
NoSuchAlgorithmException, InvalidKeySpecException, InvalidParameterSpecException {
|
||||
KeyFactory kf = KeyFactory.getInstance(EC);
|
||||
int mid = rawBytes.length / 2;
|
||||
byte[] x = Arrays.copyOfRange(rawBytes, 0, mid);
|
||||
byte[] y = Arrays.copyOfRange(rawBytes, mid, rawBytes.length);
|
||||
ECPoint w = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));
|
||||
return (ECPublicKey) kf.generatePublic(new ECPublicKeySpec(w, ecParameterSpecForCurve(curveName)));
|
||||
}
|
||||
|
||||
public static ECParameterSpec ecParameterSpecForCurve(String curveName) throws
|
||||
NoSuchAlgorithmException, InvalidParameterSpecException {
|
||||
AlgorithmParameters params = AlgorithmParameters.getInstance(EC);
|
||||
params.init(new ECGenParameterSpec(curveName));
|
||||
return params.getParameterSpec(ECParameterSpec.class);
|
||||
}
|
||||
|
||||
public static byte[] generateSharedSecret(PrivateKey privateKey,
|
||||
PublicKey publicKey) {
|
||||
try {
|
||||
KeyAgreement keyAgreement = KeyAgreement.getInstance(ECDH);
|
||||
keyAgreement.init(privateKey);
|
||||
keyAgreement.doPhase(publicKey, true);
|
||||
|
||||
return keyAgreement.generateSecret();
|
||||
} catch (InvalidKeyException | NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// Single Scheduler all callback must be observed on
|
||||
//==============================================================================================
|
||||
|
||||
private static final Scheduler SS = Schedulers.single();
|
||||
|
||||
public BleConnectionState getPatchConnectionState() {
|
||||
return patch.getConnectionState();
|
||||
}
|
||||
|
||||
public Observable<BleConnectionState> observePatchConnectionState() {
|
||||
return patch.observeConnectionState();
|
||||
}
|
||||
|
||||
public void updateMacAddress(String mac, boolean b){
|
||||
patch.updateMacAddress(mac, b);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.interfaces.CommandQueue;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.code.BolusType;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.FetchAlarmTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.InternalSuspendedTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.ReadBolusFinishTimeTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.task.ReadTempBasalFinishTimeTask;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.BolusCurrent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.NormalBasal;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.TempBasal;
|
||||
import io.reactivex.rxjava3.core.Maybe;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
|
||||
@Singleton
|
||||
public class PatchStateManager {
|
||||
|
||||
@Inject IPreferenceManager pm;
|
||||
@Inject ReadBolusFinishTimeTask readBolusFinishTimeTask;
|
||||
@Inject ReadTempBasalFinishTimeTask readTempBasalFinishTimeTask;
|
||||
@Inject InternalSuspendedTask internalSuspendedTask;
|
||||
@Inject FetchAlarmTask FETCH_ALARM;
|
||||
@Inject CommandQueue commandQueue;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
|
||||
@Inject
|
||||
public PatchStateManager() {
|
||||
|
||||
}
|
||||
|
||||
public synchronized void updatePatchState(PatchState newState) {
|
||||
Maybe.fromCallable(() -> newState).observeOn(Schedulers.single())
|
||||
.doOnSuccess(patchState -> updatePatchStateInner(patchState))
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.doOnSuccess(patchState -> aapsLogger.debug(LTag.PUMP, patchState.toString()))
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
/* Schedulers.io() */
|
||||
public synchronized void updatePatchStateInner(PatchState newState) {
|
||||
|
||||
final PatchState oldState = pm.getPatchState();
|
||||
|
||||
int diff = newState.currentTime() - oldState.currentTime();
|
||||
if (0 <= diff && diff < 10) {
|
||||
/* 10초 안에 같은 PatchState update 시 skip */
|
||||
if (oldState.equalState(newState)) {
|
||||
return;
|
||||
}
|
||||
} else if (-5 < diff && diff < 0) {
|
||||
/* 이전 State 가 새로운 State 를 덮어 쓰는 것을 방지 -4초 까지 */
|
||||
return;
|
||||
}
|
||||
|
||||
newState.setUpdatedTimestamp(System.currentTimeMillis());
|
||||
|
||||
if (newState.isNewAlertAlarm()) {
|
||||
FETCH_ALARM.enqueue();
|
||||
}
|
||||
|
||||
if (newState.isPatchInternalSuspended()){
|
||||
onPatchInternalSuspended(newState);
|
||||
}
|
||||
|
||||
/* Normal Basal --------------------------------------------------------------------------------------------- */
|
||||
|
||||
if (newState.isNormalBasalAct()) {
|
||||
if (oldState.isNormalBasalPaused()) {
|
||||
// Resume --> onBasalResume
|
||||
onBasalResumeState();
|
||||
|
||||
} else if (oldState.isNormalBasalAct() == false) {
|
||||
// Start --> onBasalStarted
|
||||
}
|
||||
} else if (oldState.isNormalBasalPaused() == false && newState.isNormalBasalPaused()) {
|
||||
if (newState.isTempBasalAct()) {
|
||||
} else {
|
||||
// pause
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Temp Basal ------------------------------------------------------------------------------------------- */
|
||||
if (newState.isTempBasalAct()) {
|
||||
if (oldState.isTempBasalAct() == false) {
|
||||
// Start
|
||||
onTempBasalStartState();
|
||||
}
|
||||
}
|
||||
|
||||
boolean tempBasalStopped = false;
|
||||
boolean tempBasalFinished = false;
|
||||
|
||||
if (newState.isTempBasalDone() && !newState.isPatchInternalSuspended()) {
|
||||
tempBasalFinished = true;
|
||||
}
|
||||
|
||||
if (oldState.isTempBasalDone() == false) {
|
||||
if (newState.isTempBasalDone()) {
|
||||
tempBasalStopped = true;
|
||||
|
||||
onTempBasalDoneState();
|
||||
} else if (oldState.isTempBasalAct() && newState.isTempBasalAct() == false) {
|
||||
tempBasalStopped = true;
|
||||
|
||||
onTempBasalCancelState();
|
||||
}
|
||||
}
|
||||
|
||||
if (tempBasalStopped) {
|
||||
if (newState.isNormalBasalAct()) {
|
||||
if (!newState.isPatchInternalSuspended()) {
|
||||
onNormalBasalResumed(tempBasalFinished);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newState.isTempBasalAct() == false && pm.getTempBasalManager().getStartedBasal() != null) {
|
||||
pm.getTempBasalManager().updateBasalStopped();
|
||||
}
|
||||
|
||||
/* Now Bolus -------------------------------------------------------------------------------------------- */
|
||||
if (oldState.isNowBolusRegAct() == false && newState.isNowBolusRegAct() == true) {
|
||||
// Start
|
||||
} else if (oldState.isNowBolusDone() == false) {
|
||||
if (oldState.isNowBolusRegAct() && newState.isNowBolusRegAct() == false) {
|
||||
// Cancel
|
||||
} else if (newState.isNowBolusDone()) {
|
||||
// Done
|
||||
}
|
||||
}
|
||||
|
||||
BolusCurrent bolusCurrent = pm.getBolusCurrent();
|
||||
|
||||
if (newState.isNowBolusRegAct() == false && bolusCurrent.historyId(BolusType.NOW) > 0
|
||||
&& bolusCurrent.endTimeSynced(BolusType.NOW)) {
|
||||
bolusCurrent.clearBolus(BolusType.NOW);
|
||||
}
|
||||
|
||||
/* Extended Bolus --------------------------------------------------------------------------------------- */
|
||||
if (oldState.isExtBolusRegAct() == false && newState.isExtBolusRegAct() == true) {
|
||||
// Start
|
||||
} else if (oldState.isExtBolusDone() == false) {
|
||||
if (oldState.isExtBolusRegAct() && newState.isExtBolusRegAct() == false) {
|
||||
// Cancel
|
||||
} else if (newState.isExtBolusDone()) {
|
||||
// Done
|
||||
}
|
||||
}
|
||||
|
||||
if (newState.isExtBolusRegAct() == false && bolusCurrent.historyId(BolusType.EXT) > 0
|
||||
&& bolusCurrent.endTimeSynced(BolusType.EXT)) {
|
||||
bolusCurrent.clearBolus(BolusType.EXT);
|
||||
}
|
||||
|
||||
/* Finish Time Sync and remained insulin update*/
|
||||
/* Bolus Done -> update finish time */
|
||||
if (Stream.of(BolusType.NOW, BolusType.EXT).anyMatch(type ->
|
||||
newState.isBolusDone(type) && !bolusCurrent.endTimeSynced(type))) {
|
||||
readBolusFinishTime();
|
||||
}
|
||||
|
||||
/* TempBasal Done -> update finish time */
|
||||
if (tempBasalFinished) {
|
||||
readTempBasalFinishTime();
|
||||
}
|
||||
|
||||
/* Remained Insulin update */
|
||||
if (newState.getRemainedInsulin() != oldState.getRemainedInsulin()) {
|
||||
pm.getPatchConfig().setRemainedInsulin(newState.getRemainedInsulin());
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
|
||||
pm.getPatchState().update(newState);
|
||||
pm.flushPatchState();
|
||||
}
|
||||
|
||||
private void onTempBasalStartState() {
|
||||
TempBasal tempBasal = pm.getTempBasalManager().getStartedBasal();
|
||||
|
||||
if (tempBasal != null) {
|
||||
pm.getPatchConfig().updateTempBasalStarted();
|
||||
|
||||
NormalBasal normalBasal = pm.getNormalBasalManager().getNormalBasal();
|
||||
|
||||
if (normalBasal != null) {
|
||||
pm.getNormalBasalManager().updateBasalPaused();
|
||||
}
|
||||
|
||||
pm.flushPatchConfig();
|
||||
pm.flushNormalBasalManager();
|
||||
}
|
||||
}
|
||||
|
||||
void onTempBasalDoneState() {
|
||||
TempBasal tempBasal = pm.getTempBasalManager().getStartedBasal();
|
||||
|
||||
if (tempBasal != null) {
|
||||
pm.getTempBasalManager().updateBasalStopped();
|
||||
pm.flushTempBasalManager();
|
||||
}
|
||||
}
|
||||
|
||||
private void onTempBasalCancelState() {
|
||||
TempBasal tempBasal = pm.getTempBasalManager().getStartedBasal();
|
||||
|
||||
if (tempBasal != null) {
|
||||
pm.getTempBasalManager().updateBasalStopped();
|
||||
pm.flushTempBasalManager();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void readBolusFinishTime() {
|
||||
readBolusFinishTimeTask.enqueue();
|
||||
}
|
||||
|
||||
private void readTempBasalFinishTime() {
|
||||
readTempBasalFinishTimeTask.enqueue();
|
||||
}
|
||||
|
||||
private synchronized void onBasalResumeState() {
|
||||
|
||||
if (!pm.getNormalBasalManager().isStarted()) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
onBasalResumed(timestamp + 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void onNormalBasalResumed(boolean tempBasalFinished) {
|
||||
NormalBasal normalBasal = pm.getNormalBasalManager().getNormalBasal();
|
||||
if (normalBasal != null) {
|
||||
pm.getNormalBasalManager().updateBasalStarted();
|
||||
normalBasal.updateNormalBasalIndex();
|
||||
pm.flushNormalBasalManager();;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void onBasalResumed(long timestamp) {
|
||||
if (!pm.getNormalBasalManager().isStarted()) {
|
||||
pm.getNormalBasalManager().updateBasalStarted();
|
||||
|
||||
pm.getPatchConfig().updateNormalBasalStarted();
|
||||
pm.getPatchConfig().setNeedSetBasalSchedule(false);
|
||||
|
||||
NormalBasal basal = pm.getNormalBasalManager().getNormalBasal();
|
||||
|
||||
if (basal != null) {
|
||||
basal.updateNormalBasalIndex();
|
||||
}
|
||||
|
||||
pm.flushPatchConfig();
|
||||
pm.flushNormalBasalManager();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void onBasalStarted(NormalBasal basal, long timestamp) {
|
||||
if (basal != null) {
|
||||
pm.getNormalBasalManager().updateBasalStarted();
|
||||
basal.updateNormalBasalIndex();
|
||||
}
|
||||
|
||||
pm.getPatchConfig().updateNormalBasalStarted(); // updateNormalBasalStarted 도 동일함...
|
||||
pm.getPatchConfig().setNeedSetBasalSchedule(false);
|
||||
|
||||
pm.flushPatchConfig();
|
||||
pm.flushNormalBasalManager();
|
||||
}
|
||||
|
||||
private void onPatchInternalSuspended(PatchState state) {
|
||||
boolean isNowBolusActive = state.isNowBolusActive();
|
||||
boolean isExtBolusActive = state.isExtBolusActive();
|
||||
boolean isTempBasalActive = state.isTempBasalActive();
|
||||
|
||||
if (isNowBolusActive || isExtBolusActive || isTempBasalActive) {
|
||||
internalSuspendedTask.enqueue(isNowBolusActive, isExtBolusActive, isTempBasalActive);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble
|
||||
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.GsonHelper
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.SettingKeys
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.PatchLifecycle
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.*
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
interface IPreferenceManager {
|
||||
fun getPatchConfig(): PatchConfig
|
||||
fun getPatchState(): PatchState
|
||||
fun getBolusCurrent(): BolusCurrent
|
||||
fun getNormalBasalManager(): NormalBasalManager
|
||||
fun getTempBasalManager(): TempBasalManager
|
||||
fun getAlarms(): Alarms
|
||||
fun init()
|
||||
fun flushPatchConfig()
|
||||
fun flushPatchState()
|
||||
fun flushBolusCurrent()
|
||||
fun flushNormalBasalManager()
|
||||
fun flushTempBasalManager()
|
||||
fun flushAlarms()
|
||||
fun updatePatchLifeCycle(event: PatchLifecycleEvent)
|
||||
fun updatePatchState(newState: PatchState)
|
||||
fun getPatchSerial(): String
|
||||
fun getPatchMac(): String?
|
||||
fun isActivated(): Boolean
|
||||
fun setMacAddress(mac: String)
|
||||
fun getPatchExpiredTime(): Long
|
||||
fun setSharedKey(bytes: ByteArray?)
|
||||
fun setSeq15(seq15: Int)
|
||||
fun getSeq15(): Int
|
||||
fun increaseSeq15()
|
||||
fun getPatchWakeupTimestamp(): Long
|
||||
fun observePatchLifeCycle(): Observable<PatchLifecycle>
|
||||
fun observePatchConfig(): Observable<PatchConfig>
|
||||
fun observePatchState(): Observable<PatchState>
|
||||
fun observeBolusCurrent(): Observable<BolusCurrent>
|
||||
fun observeAlarm(): Observable<Alarms>
|
||||
fun isInitDone(): Boolean
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* patch2 패키지에서 사용하는 프리퍼런스의 작업을 대신 처리하는 클래스
|
||||
*/
|
||||
@Singleton
|
||||
class PreferenceManager @Inject constructor(): IPreferenceManager {
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var mPatchConfig: PatchConfig
|
||||
@Inject lateinit var mNormalBasalMgr: NormalBasalManager
|
||||
@Inject lateinit var mTempBasalMgr: TempBasalManager
|
||||
@Inject lateinit var mAlarms: Alarms
|
||||
|
||||
private var mPatchState = PatchState()
|
||||
private var mBolusCurrent = BolusCurrent()
|
||||
private lateinit var observePatchLifeCycle: Observable<PatchLifecycle>
|
||||
private var initialized = false
|
||||
|
||||
@Inject
|
||||
fun onInit() {
|
||||
observePatchLifeCycle = mPatchConfig.observe()
|
||||
.map { patchConfig -> patchConfig.lifecycleEvent.lifeCycle }
|
||||
.distinctUntilChanged()
|
||||
.replay(1).refCount()
|
||||
}
|
||||
|
||||
override fun getPatchConfig(): PatchConfig {
|
||||
return mPatchConfig
|
||||
}
|
||||
|
||||
override fun getPatchState(): PatchState {
|
||||
return mPatchState
|
||||
}
|
||||
|
||||
override fun getBolusCurrent(): BolusCurrent {
|
||||
return mBolusCurrent
|
||||
}
|
||||
|
||||
override fun getNormalBasalManager(): NormalBasalManager {
|
||||
return mNormalBasalMgr
|
||||
}
|
||||
|
||||
override fun getTempBasalManager(): TempBasalManager {
|
||||
return mTempBasalMgr
|
||||
}
|
||||
|
||||
override fun getAlarms(): Alarms {
|
||||
return mAlarms
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
try {
|
||||
val jsonStr = sp.getString(SettingKeys.PATCH_STATE, "")
|
||||
val savedState = GsonHelper.sharedGson().fromJson(jsonStr, PatchState::class.java)
|
||||
mPatchState = savedState
|
||||
} catch (ex: Exception) {
|
||||
mPatchState = PatchState()
|
||||
aapsLogger.error(LTag.PUMP, ex.message?:"PatchState load error")
|
||||
}
|
||||
|
||||
try {
|
||||
val jsonStr = sp.getString(SettingKeys.BOLUS_CURRENT, "")
|
||||
val savedBolusCurrent = GsonHelper.sharedGson().fromJson(jsonStr, BolusCurrent::class.java)
|
||||
mBolusCurrent = savedBolusCurrent
|
||||
} catch (ex: Exception) {
|
||||
mBolusCurrent = BolusCurrent()
|
||||
aapsLogger.error(LTag.PUMP, ex.message?:"BolusCurrent load error")
|
||||
}
|
||||
|
||||
try {
|
||||
val jsonStr = sp.getString(SettingKeys.PATCH_CONFIG, "")
|
||||
val savedConfig = GsonHelper.sharedGson().fromJson(jsonStr, PatchConfig::class.java)
|
||||
mPatchConfig.update(savedConfig)
|
||||
} catch (ex: Exception) {
|
||||
aapsLogger.error(LTag.PUMP, ex.message?:"PatchConfig load error")
|
||||
}
|
||||
|
||||
try {
|
||||
val jsonStr = sp.getString(SettingKeys.NORMAL_BASAL, "")
|
||||
val normalBasalManager = GsonHelper.sharedGson().fromJson(jsonStr, NormalBasalManager::class.java)
|
||||
mNormalBasalMgr.update(normalBasalManager)
|
||||
} catch (ex: Exception) {
|
||||
aapsLogger.error(LTag.PUMP, ex.message?:"NormalBasal load error")
|
||||
}
|
||||
|
||||
try {
|
||||
val jsonStr = sp.getString(SettingKeys.TEMP_BASAL, "")
|
||||
val tempBasalManager = GsonHelper.sharedGson().fromJson(jsonStr, TempBasalManager::class.java)
|
||||
mTempBasalMgr.update(tempBasalManager)
|
||||
} catch (ex: Exception) {
|
||||
aapsLogger.error(LTag.PUMP, ex.message?:"TempBasal load error")
|
||||
}
|
||||
|
||||
try {
|
||||
val jsonStr = sp.getString(SettingKeys.ALARMS, "")
|
||||
val alarms = GsonHelper.sharedGson().fromJson(jsonStr, Alarms::class.java)
|
||||
mAlarms.update(alarms)
|
||||
} catch (ex: Exception) {
|
||||
aapsLogger.error(LTag.PUMP, ex.message?:"Alarms load error")
|
||||
}
|
||||
|
||||
aapsLogger.info(LTag.PUMP,"Load from PatchConfig preference: $mPatchConfig")
|
||||
aapsLogger.info(LTag.PUMP,"Load from PatchState preference: $mPatchState")
|
||||
aapsLogger.info(LTag.PUMP,"Load from BolusCurrent preference: $mBolusCurrent")
|
||||
aapsLogger.info(LTag.PUMP,"Load from NormalBasal preference: $mNormalBasalMgr")
|
||||
aapsLogger.info(LTag.PUMP,"Load from TempBasal preference: $mTempBasalMgr")
|
||||
aapsLogger.info(LTag.PUMP,"Load from Alarms preference: $mAlarms")
|
||||
initialized = true
|
||||
}
|
||||
|
||||
override fun isInitDone() = initialized
|
||||
|
||||
override fun flushPatchConfig() = mPatchConfig.flush(sp)
|
||||
override fun flushPatchState() = mPatchState.flush(sp)
|
||||
override fun flushBolusCurrent() = mBolusCurrent.flush(sp)
|
||||
override fun flushNormalBasalManager() = mNormalBasalMgr.flush(sp)
|
||||
override fun flushTempBasalManager() = mTempBasalMgr.flush(sp)
|
||||
override fun flushAlarms() = mAlarms.flush(sp)
|
||||
|
||||
@Synchronized
|
||||
override fun updatePatchLifeCycle(event: PatchLifecycleEvent) {
|
||||
mPatchConfig.updateLifecycle(event)
|
||||
flushPatchConfig()
|
||||
|
||||
when (event.lifeCycle) {
|
||||
PatchLifecycle.SHUTDOWN -> {
|
||||
mPatchState.clear()
|
||||
flushPatchState()
|
||||
mBolusCurrent.clearAll()
|
||||
flushBolusCurrent()
|
||||
mTempBasalMgr.clear()
|
||||
flushTempBasalManager()
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun updatePatchState(newState: PatchState) {
|
||||
mPatchState = newState
|
||||
flushPatchState()
|
||||
}
|
||||
|
||||
override fun getPatchSerial(): String {
|
||||
return mPatchConfig.patchSerialNumber
|
||||
}
|
||||
|
||||
override fun getPatchMac(): String? {
|
||||
return mPatchConfig.macAddress
|
||||
}
|
||||
|
||||
override fun isActivated(): Boolean {
|
||||
return mPatchConfig.isActivated
|
||||
}
|
||||
|
||||
override fun setMacAddress(mac: String) {
|
||||
mPatchConfig.macAddress = mac
|
||||
flushPatchConfig()
|
||||
}
|
||||
|
||||
override fun getPatchExpiredTime(): Long {
|
||||
return mPatchConfig.getPatchExpiredTime()
|
||||
}
|
||||
|
||||
override fun setSharedKey(bytes: ByteArray?) {
|
||||
mPatchConfig.sharedKey = bytes
|
||||
}
|
||||
|
||||
override fun setSeq15(seq15: Int) {
|
||||
mPatchConfig.seq15 = seq15
|
||||
}
|
||||
|
||||
override fun getSeq15(): Int {
|
||||
return mPatchConfig.seq15
|
||||
}
|
||||
|
||||
override fun increaseSeq15() {
|
||||
mPatchConfig.incSeq()
|
||||
}
|
||||
|
||||
override fun getPatchWakeupTimestamp(): Long {
|
||||
return mPatchConfig.patchWakeupTimestamp
|
||||
}
|
||||
|
||||
override fun observePatchLifeCycle(): Observable<PatchLifecycle> {
|
||||
return observePatchLifeCycle
|
||||
}
|
||||
|
||||
override fun observePatchConfig(): Observable<PatchConfig> {
|
||||
return mPatchConfig.observe()
|
||||
}
|
||||
|
||||
override fun observePatchState(): Observable<PatchState> {
|
||||
return mPatchState.observe()
|
||||
}
|
||||
|
||||
override fun observeBolusCurrent(): Observable<BolusCurrent>{
|
||||
return mBolusCurrent.observe()
|
||||
}
|
||||
|
||||
override fun observeAlarm(): Observable<Alarms> {
|
||||
return mAlarms.observe()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.SetKey;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BaseResponse;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.NormalBasal;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchLifecycleEvent;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
@Singleton
|
||||
public class ActivateTask extends TaskBase {
|
||||
@Inject StartNormalBasalTask startBasalTask;
|
||||
|
||||
private final SetKey SET_KEY = new SetKey();
|
||||
|
||||
@Inject
|
||||
public ActivateTask() {
|
||||
super(TaskFunc.ACTIVATE);
|
||||
}
|
||||
|
||||
public Single<Boolean> start() {
|
||||
NormalBasal enabled = pm.getNormalBasalManager().getNormalBasal();
|
||||
return isReady()
|
||||
.concatMapSingle(v -> SET_KEY.setKey())
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.observeOn(Schedulers.io())
|
||||
.flatMap(v -> startBasalTask.start(enabled))
|
||||
.doOnSuccess(this::onActivated)
|
||||
.map(BaseResponse::isSuccess)
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "ActivateTask error"));
|
||||
}
|
||||
|
||||
private void onActivated(BaseResponse response) {
|
||||
pm.updatePatchLifeCycle(PatchLifecycleEvent.createActivated());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.BolusExDuration;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.AppConstant;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.code.BolusType;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.util.FloatAdjusters;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.BolusCurrent;
|
||||
|
||||
abstract class BolusTask extends TaskBase {
|
||||
|
||||
public BolusTask(TaskFunc func) {
|
||||
super(func);
|
||||
}
|
||||
|
||||
public void onQuickBolusStarted(float nowDoseU, float exDoseU, BolusExDuration exDuration) {
|
||||
boolean now = (nowDoseU > 0);
|
||||
boolean ext = (exDoseU > 0);
|
||||
|
||||
long startTimestamp = now ? System.currentTimeMillis() : 0;
|
||||
long endTimestamp = startTimestamp + getPumpDuration(nowDoseU);
|
||||
|
||||
long nowHistoryID = 1L; //record no
|
||||
long exStartTimestamp;
|
||||
|
||||
if (now) {
|
||||
pm.getBolusCurrent().startNowBolus(nowHistoryID, nowDoseU, startTimestamp, endTimestamp);
|
||||
}
|
||||
if (ext) {
|
||||
long estimatedExStartTimestamp;
|
||||
|
||||
if (now) {
|
||||
exStartTimestamp = 0;
|
||||
}
|
||||
else {
|
||||
estimatedExStartTimestamp = System.currentTimeMillis();
|
||||
exStartTimestamp = estimatedExStartTimestamp;
|
||||
}
|
||||
long exEndTimestamp = exStartTimestamp + exDuration.milli();
|
||||
|
||||
long extHistoryID = 2L; //record no
|
||||
pm.getBolusCurrent().startExtBolus(extHistoryID, exDoseU, exStartTimestamp,
|
||||
exEndTimestamp, exDuration.milli());
|
||||
}
|
||||
|
||||
pm.flushBolusCurrent();
|
||||
}
|
||||
|
||||
|
||||
public void onCalcBolusStarted(float nowDoseU) {
|
||||
boolean now = (nowDoseU > 0);
|
||||
|
||||
long startTimestamp = now ? System.currentTimeMillis() : 0; // dm_1720
|
||||
long endTimestamp = startTimestamp + getPumpDuration(nowDoseU);
|
||||
|
||||
long nowHistoryID = 1L; //record no
|
||||
|
||||
if (now) {
|
||||
pm.getBolusCurrent().startNowBolus(nowHistoryID, nowDoseU, startTimestamp, endTimestamp);
|
||||
}
|
||||
|
||||
pm.flushBolusCurrent();
|
||||
}
|
||||
|
||||
public void updateNowBolusStopped(int injected) {
|
||||
updateNowBolusStopped(injected, 0);
|
||||
}
|
||||
|
||||
public void updateNowBolusStopped(int injected, long suspendedTimestamp) {
|
||||
BolusCurrent bolusCurrent = pm.getBolusCurrent();
|
||||
long nowID = bolusCurrent.historyId(BolusType.NOW);
|
||||
if (nowID > 0 && !bolusCurrent.endTimeSynced(BolusType.NOW)) {
|
||||
long stopTime = (suspendedTimestamp > 0) ? suspendedTimestamp : System.currentTimeMillis();
|
||||
float injectedDoseU = FloatAdjusters.FLOOR2_BOLUS.apply(injected * AppConstant.INSULIN_UNIT_P);
|
||||
bolusCurrent.getNowBolus().setInjected(injectedDoseU);
|
||||
bolusCurrent.getNowBolus().setEndTimestamp(stopTime);
|
||||
bolusCurrent.setEndTimeSynced(BolusType.NOW, true);
|
||||
pm.flushBolusCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateExtBolusStopped(int injected) {
|
||||
updateExtBolusStopped(injected, 0);
|
||||
}
|
||||
|
||||
public void updateExtBolusStopped(int injected, long suspendedTimestamp) {
|
||||
BolusCurrent bolusCurrent = pm.getBolusCurrent();
|
||||
long extID = bolusCurrent.historyId(BolusType.EXT);
|
||||
if (extID > 0 && !bolusCurrent.endTimeSynced(BolusType.EXT)) {
|
||||
long stopTime = (suspendedTimestamp > 0) ? suspendedTimestamp : System.currentTimeMillis();
|
||||
float injectedDoseU = FloatAdjusters.FLOOR2_BOLUS.apply(injected * AppConstant.INSULIN_UNIT_P);
|
||||
bolusCurrent.getExtBolus().setInjected(injectedDoseU);
|
||||
bolusCurrent.getExtBolus().setEndTimestamp(stopTime);
|
||||
bolusCurrent.setEndTimeSynced(BolusType.EXT, true);
|
||||
pm.flushBolusCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
private long getPumpDuration(float doseU) {
|
||||
if (doseU > 0) {
|
||||
long pumpDuration = pm.getPatchConfig().getPumpDurationSmallMilli();
|
||||
return (long) ((doseU / AppConstant.BOLUS_UNIT_STEP) * pumpDuration);
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.DeactivationStatus;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.DeActivation;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.code.BolusType;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.BolusCurrent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchLifecycleEvent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.TempBasal;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class DeactivateTask extends TaskBase {
|
||||
@Inject StopBasalTask stopBasalTask;
|
||||
@Inject IPreferenceManager pm;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
|
||||
private final DeActivation DEACTIVATION;
|
||||
|
||||
@Inject
|
||||
public DeactivateTask() {
|
||||
super(TaskFunc.DEACTIVATE);
|
||||
DEACTIVATION = new DeActivation();
|
||||
}
|
||||
|
||||
public Single<DeactivationStatus> run(boolean forced, long timeout) {
|
||||
return isReadyCheckActivated()
|
||||
.timeout(timeout, TimeUnit.MILLISECONDS)
|
||||
.concatMapSingle(v ->
|
||||
DEACTIVATION.start()
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.doOnSuccess(response -> onDeactivated()))
|
||||
.map(response -> DeactivationStatus.of(response.isSuccess(), forced))
|
||||
.firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "DeactivateTask error"))
|
||||
.onErrorResumeNext(e -> {
|
||||
if (forced) {
|
||||
try {
|
||||
onDeactivated();
|
||||
} catch (Exception t) {
|
||||
aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "DeactivateTask error");
|
||||
}
|
||||
}
|
||||
|
||||
return Single.just(DeactivationStatus.of(false, forced));
|
||||
});
|
||||
}
|
||||
|
||||
private Observable<TaskFunc> isReadyCheckActivated() {
|
||||
if (pm.getPatchConfig().isActivated()) {
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
|
||||
stopBasalTask.enqueue();
|
||||
|
||||
return isReady2();
|
||||
}
|
||||
|
||||
return isReady();
|
||||
}
|
||||
|
||||
private void onDeactivated() {
|
||||
synchronized (lock) {
|
||||
patch.updateMacAddress(null, false);
|
||||
|
||||
if (pm.getPatchConfig().getLifecycleEvent().isShutdown()) {
|
||||
return;
|
||||
}
|
||||
cleanUpRepository();
|
||||
pm.getNormalBasalManager().updateForDeactivation();
|
||||
pm.updatePatchLifeCycle(PatchLifecycleEvent.createShutdown());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanUpRepository() {
|
||||
updateNowBolusStopped();
|
||||
updateExtBolusStopped();
|
||||
updateTempBasalStopped();
|
||||
}
|
||||
|
||||
private void updateTempBasalStopped() {
|
||||
TempBasal tempBasal = pm.getTempBasalManager().getStartedBasal();
|
||||
|
||||
if (tempBasal != null) {
|
||||
pm.getTempBasalManager().updateBasalStopped();
|
||||
pm.flushTempBasalManager();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNowBolusStopped() {
|
||||
BolusCurrent bolusCurrent = pm.getBolusCurrent();
|
||||
long nowID = bolusCurrent.historyId(BolusType.NOW);
|
||||
|
||||
if (nowID > 0 && !bolusCurrent.endTimeSynced(BolusType.NOW)) {
|
||||
bolusCurrent.setEndTimeSynced(BolusType.NOW, true);
|
||||
pm.flushBolusCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateExtBolusStopped() {
|
||||
BolusCurrent bolusCurrent = pm.getBolusCurrent();
|
||||
long extID = bolusCurrent.historyId(BolusType.EXT);
|
||||
|
||||
if (extID > 0 && !bolusCurrent.endTimeSynced(BolusType.EXT)) {
|
||||
bolusCurrent.setEndTimeSynced(BolusType.EXT, true);
|
||||
pm.flushBolusCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.IAlarmRegistry;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetErrorCodes;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.AeCodeResponse;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class FetchAlarmTask extends TaskBase {
|
||||
@Inject RxBus rxBus;
|
||||
@Inject IAlarmRegistry alarmRegistry;
|
||||
|
||||
private final GetErrorCodes ALARM_ALERT_ERROR_CODE_GET;
|
||||
|
||||
@Inject
|
||||
public FetchAlarmTask() {
|
||||
super(TaskFunc.FETCH_ALARM);
|
||||
ALARM_ALERT_ERROR_CODE_GET = new GetErrorCodes();
|
||||
}
|
||||
|
||||
public Single<AeCodeResponse> getPatchAlarm() {
|
||||
return isReady()
|
||||
.concatMapSingle(v -> ALARM_ALERT_ERROR_CODE_GET.get())
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.doOnSuccess(aeCodeResponse -> alarmRegistry.add(aeCodeResponse.getAlarmCodes()))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "FetchAlarmTask error"));
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = getPatchAlarm()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetFirmwareVersion;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetLOT;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetModelName;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetPumpDuration;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetSerialNumber;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetWakeUpTime;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.SetGlobalTime;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BaseResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.FirmwareVersionResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.LotNumberResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.ModelNameResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PumpDurationResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.SerialNumberResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.WakeUpTimeResponse;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
@Singleton
|
||||
public class GetPatchInfoTask extends TaskBase {
|
||||
@Inject UpdateConnectionTask updateConnectionTask;
|
||||
|
||||
private final SetGlobalTime SET_GLOBAL_TIME;
|
||||
private final GetSerialNumber SERIAL_NUMBER_GET;
|
||||
private final GetLOT LOT_NUMBER_GET;
|
||||
private final GetFirmwareVersion FIRMWARE_VERSION_GET;
|
||||
private final GetWakeUpTime WAKE_UP_TIME_GET;
|
||||
private final GetPumpDuration PUMP_DURATION_GET;
|
||||
private final GetModelName GET_MODEL_NAME;
|
||||
|
||||
@Inject
|
||||
public GetPatchInfoTask() {
|
||||
super(TaskFunc.GET_PATCH_INFO);
|
||||
|
||||
SET_GLOBAL_TIME = new SetGlobalTime();
|
||||
SERIAL_NUMBER_GET = new GetSerialNumber();
|
||||
LOT_NUMBER_GET = new GetLOT();
|
||||
FIRMWARE_VERSION_GET = new GetFirmwareVersion();
|
||||
WAKE_UP_TIME_GET = new GetWakeUpTime();
|
||||
PUMP_DURATION_GET = new GetPumpDuration();
|
||||
GET_MODEL_NAME = new GetModelName();
|
||||
}
|
||||
|
||||
public Single<Boolean> get() {
|
||||
Single<Boolean> tasks = Single.concat(Arrays.asList(
|
||||
SET_GLOBAL_TIME.set(),
|
||||
SERIAL_NUMBER_GET.get().doOnSuccess(this::onSerialNumberResponse),
|
||||
LOT_NUMBER_GET.get().doOnSuccess(this::onLotNumberResponse),
|
||||
FIRMWARE_VERSION_GET.get().doOnSuccess(this::onFirmwareResponse),
|
||||
WAKE_UP_TIME_GET.get().doOnSuccess(this::onWakeupTimeResponse),
|
||||
PUMP_DURATION_GET.get().doOnSuccess(this::onPumpDurationResponse),
|
||||
GET_MODEL_NAME.get().doOnSuccess(this::onModelNameResponse)))
|
||||
.map(BaseResponse::isSuccess)
|
||||
.filter(v -> !v)
|
||||
.first(true);
|
||||
|
||||
return isReady()
|
||||
.concatMapSingle(it -> tasks)
|
||||
.firstOrError()
|
||||
.observeOn(Schedulers.io())
|
||||
.doOnSuccess(this::onPatchWakeupSuccess)
|
||||
.doOnError(this::onPatchWakeupFailed)
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "GetPatchInfoTask error"));
|
||||
}
|
||||
|
||||
private void onSerialNumberResponse(SerialNumberResponse v) {
|
||||
pm.getPatchConfig().setPatchSerialNumber(v.getSerialNumber());
|
||||
}
|
||||
|
||||
private void onLotNumberResponse(LotNumberResponse v) {
|
||||
pm.getPatchConfig().setPatchLotNumber(v.getLotNumber());
|
||||
}
|
||||
|
||||
private void onFirmwareResponse(FirmwareVersionResponse v) {
|
||||
pm.getPatchConfig().setPatchFirmwareVersion(v.getFirmwareVersionString());
|
||||
}
|
||||
|
||||
private void onWakeupTimeResponse(WakeUpTimeResponse v) {
|
||||
pm.getPatchConfig().setPatchWakeupTimestamp(v.getTimeInMillis());
|
||||
}
|
||||
|
||||
private void onPumpDurationResponse(PumpDurationResponse v) {
|
||||
pm.getPatchConfig().setPumpDurationLargeMilli(v.getDurationL() * 100L);
|
||||
pm.getPatchConfig().setPumpDurationMediumMilli(v.getDurationM() * 100L);
|
||||
pm.getPatchConfig().setPumpDurationSmallMilli(v.getDurationS() * 100L);
|
||||
}
|
||||
|
||||
private void onModelNameResponse(ModelNameResponse modelNameResponse) {
|
||||
pm.getPatchConfig().setPatchModelName(modelNameResponse.getModelName());
|
||||
}
|
||||
|
||||
private void onPatchWakeupSuccess(Boolean result) {
|
||||
synchronized (lock) {
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void onPatchWakeupFailed(Throwable e) {
|
||||
patch.setSeq(-1);
|
||||
pm.getPatchConfig().updateDeactivated();
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.InfoReminderSet;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class InfoReminderTask extends TaskBase {
|
||||
@Inject IPreferenceManager pm;
|
||||
|
||||
private final InfoReminderSet INFO_REMINDER_SET;
|
||||
|
||||
@Inject
|
||||
public InfoReminderTask() {
|
||||
super(TaskFunc.INFO_REMINDER);
|
||||
INFO_REMINDER_SET = new InfoReminderSet();
|
||||
}
|
||||
|
||||
/* alert delay 사용안함 */
|
||||
public Single<PatchBooleanResponse> set(boolean infoReminder) {
|
||||
return isReady()
|
||||
.concatMapSingle(v -> INFO_REMINDER_SET.set(infoReminder))
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "InfoReminderTask error"));
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = set(pm.getPatchConfig().getInfoReminder())
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import info.nightscout.androidaps.interfaces.PumpSync;
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger;
|
||||
import info.nightscout.androidaps.utils.userEntry.UserEntryMapper;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.interfaces.CommandQueue;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetInternalSuspendTime;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchInternalSuspendTimeResponse;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.queue.commands.Command;
|
||||
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||
|
||||
@Singleton
|
||||
public class InternalSuspendedTask extends BolusTask {
|
||||
@Inject CommandQueue commandQueue;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject PumpSync pumpSync;
|
||||
@Inject UserEntryLogger uel;
|
||||
|
||||
private final GetInternalSuspendTime INTERNAL_SUSPEND_TIME_GET;
|
||||
private final BehaviorSubject<Boolean> bolusCheckSubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Boolean> extendedBolusCheckSubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Boolean> basalCheckSubject = BehaviorSubject.create();
|
||||
|
||||
@Inject
|
||||
public InternalSuspendedTask() {
|
||||
super(TaskFunc.INTERNAL_SUSPEND);
|
||||
|
||||
INTERNAL_SUSPEND_TIME_GET = new GetInternalSuspendTime();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getBolusSubject(){
|
||||
return bolusCheckSubject.hide();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getExtendedBolusSubject(){
|
||||
return extendedBolusCheckSubject.hide();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getBasalSubject(){
|
||||
return basalCheckSubject.hide();
|
||||
}
|
||||
|
||||
public Single<Long> start(boolean isNowBolusActive, boolean isExtBolusActive, boolean isTempBasalActive) {
|
||||
if (isNowBolusActive || isExtBolusActive) {
|
||||
enqueue(TaskFunc.READ_BOLUS_FINISH_TIME);
|
||||
}
|
||||
|
||||
if (isTempBasalActive) {
|
||||
enqueue(TaskFunc.READ_TEMP_BASAL_FINISH_TIME);
|
||||
}
|
||||
|
||||
if (commandQueue.isRunning(Command.CommandType.BOLUS)) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_BOLUS, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelAllBoluses(null);
|
||||
SystemClock.sleep(650);
|
||||
}
|
||||
bolusCheckSubject.onNext(true);
|
||||
|
||||
if (pumpSync.expectedPumpState().getExtendedBolus() != null) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_EXTENDED_BOLUS, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelExtended(new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
extendedBolusCheckSubject.onNext(true);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
extendedBolusCheckSubject.onNext(true);
|
||||
}
|
||||
|
||||
if (pumpSync.expectedPumpState().getTemporaryBasal() != null) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_TEMP_BASAL, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelTempBasal(true, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
basalCheckSubject.onNext(true);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
basalCheckSubject.onNext(true);
|
||||
}
|
||||
|
||||
return Observable.zip(getBolusSubject(), getExtendedBolusSubject(), getBasalSubject(),
|
||||
(bolusReady, extendedBolusReady, basalReady) -> (bolusReady && extendedBolusReady && basalReady))
|
||||
.filter(ready -> ready)
|
||||
.flatMap(v -> isReady())
|
||||
.concatMapSingle(v -> getInternalSuspendTime())
|
||||
.firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "InternalSuspendedTask error"));
|
||||
}
|
||||
|
||||
private Single<Long> getInternalSuspendTime() {
|
||||
return INTERNAL_SUSPEND_TIME_GET.get()
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.map(PatchInternalSuspendTimeResponse::getTotalSeconds);
|
||||
}
|
||||
|
||||
public synchronized void enqueue(boolean isNowBolusActive, boolean isExtBolusActive, boolean isTempBasalActive) {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = start(isNowBolusActive, isExtBolusActive, isTempBasalActive)
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe(v -> {
|
||||
bolusCheckSubject.onNext(false);
|
||||
extendedBolusCheckSubject.onNext(false);
|
||||
basalCheckSubject.onNext(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.IAlarmRegistry;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.StartNeedleCheck;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.UpdateConnection;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class NeedleSensingTask extends TaskBase {
|
||||
@Inject IAlarmRegistry alarmRegistry;
|
||||
|
||||
StartNeedleCheck START_NEEDLE_CHECK;
|
||||
UpdateConnection UPDATE_CONNECTION;
|
||||
|
||||
@Inject
|
||||
public NeedleSensingTask() {
|
||||
super(TaskFunc.NEEDLE_SENSING);
|
||||
START_NEEDLE_CHECK = new StartNeedleCheck();
|
||||
UPDATE_CONNECTION = new UpdateConnection();
|
||||
}
|
||||
|
||||
public Single<Boolean> start() {
|
||||
|
||||
return isReady()
|
||||
.concatMapSingle(v -> START_NEEDLE_CHECK.start())
|
||||
.doOnNext(this::checkResponse)
|
||||
.concatMapSingle(v -> UPDATE_CONNECTION.get())
|
||||
.doOnNext(this::checkResponse)
|
||||
.map(updateConnectionResponse -> PatchState.Companion.create(updateConnectionResponse.getPatchState(), System.currentTimeMillis()))
|
||||
.doOnNext(this::onResponse)
|
||||
.map(patchState -> !patchState.isNeedNeedleSensing())
|
||||
.firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "NeedleSensingTask error"));
|
||||
}
|
||||
|
||||
private void onResponse(PatchState v) {
|
||||
if (v.isNeedNeedleSensing()) {
|
||||
alarmRegistry.add(AlarmCode.A016, 0, false).subscribe();
|
||||
} else {
|
||||
alarmRegistry.remove(AlarmCode.A016).subscribe();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.interfaces.CommandQueue;
|
||||
import info.nightscout.androidaps.interfaces.PumpSync;
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger;
|
||||
import info.nightscout.androidaps.utils.userEntry.UserEntryMapper;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.IAlarmRegistry;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BasalPause;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.queue.commands.Command;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||
|
||||
@Singleton
|
||||
public class PauseBasalTask extends BolusTask {
|
||||
@Inject IAlarmRegistry alarmRegistry;
|
||||
@Inject IPreferenceManager pm;
|
||||
@Inject CommandQueue commandQueue;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject PumpSync pumpSync;
|
||||
@Inject UserEntryLogger uel;
|
||||
|
||||
private final BasalPause BASAL_PAUSE;
|
||||
|
||||
private final BehaviorSubject<Boolean> bolusCheckSubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Boolean> extendedBolusCheckSubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Boolean> basalCheckSubject = BehaviorSubject.create();
|
||||
|
||||
@Inject
|
||||
public PauseBasalTask() {
|
||||
super(TaskFunc.PAUSE_BASAL);
|
||||
|
||||
BASAL_PAUSE = new BasalPause();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getBolusSubject(){
|
||||
return bolusCheckSubject.hide();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getExtendedBolusSubject(){
|
||||
return extendedBolusCheckSubject.hide();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getBasalSubject(){
|
||||
return basalCheckSubject.hide();
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> pause(float pauseDurationHour, long pausedTimestamp, @Nullable AlarmCode alarmCode) {
|
||||
PatchState patchState = pm.getPatchState();
|
||||
|
||||
if(patchState.isNormalBasalPaused())
|
||||
return Single.just(new PatchBooleanResponse(true));
|
||||
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
|
||||
if (commandQueue.isRunning(Command.CommandType.BOLUS)) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_BOLUS, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelAllBoluses(null);
|
||||
SystemClock.sleep(650);
|
||||
}
|
||||
bolusCheckSubject.onNext(true);
|
||||
|
||||
if (pumpSync.expectedPumpState().getExtendedBolus() != null) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_EXTENDED_BOLUS, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelExtended(new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
extendedBolusCheckSubject.onNext(true);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
extendedBolusCheckSubject.onNext(true);
|
||||
}
|
||||
|
||||
if (pumpSync.expectedPumpState().getTemporaryBasal() != null) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_TEMP_BASAL, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelTempBasal(true, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
basalCheckSubject.onNext(true);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
basalCheckSubject.onNext(true);
|
||||
}
|
||||
|
||||
return Observable.zip(getBolusSubject(), getExtendedBolusSubject(), getBasalSubject(),
|
||||
(bolusReady, extendedBolusReady, basalReady) -> (bolusReady && extendedBolusReady && basalReady))
|
||||
.filter(ready -> ready)
|
||||
.flatMap(v -> isReady())
|
||||
.concatMapSingle(v -> getSuspendedTime(pausedTimestamp))
|
||||
.concatMapSingle(suspendedTimestamp -> pauseBasal(pauseDurationHour, alarmCode))
|
||||
.firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "PauseBasalTask error"));
|
||||
}
|
||||
|
||||
private Single<Long> getSuspendedTime(long pausedTimestamp) {
|
||||
return Single.just(pausedTimestamp);
|
||||
}
|
||||
|
||||
private Single<PatchBooleanResponse> pauseBasal(float pauseDurationHour, @Nullable AlarmCode alarmCode) {
|
||||
if(alarmCode == null) {
|
||||
return BASAL_PAUSE.pause(pauseDurationHour)
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.doOnSuccess(v -> onBasalPaused(pauseDurationHour, null));
|
||||
}
|
||||
|
||||
// 정지 알람 발생 시 basal pause 커맨드 전달하지 않음 - 주입 정지 이력만 생성
|
||||
onBasalPaused(pauseDurationHour, alarmCode);
|
||||
|
||||
return Single.just(new PatchBooleanResponse(true));
|
||||
}
|
||||
|
||||
private void onBasalPaused(float pauseDurationHour, @Nullable AlarmCode alarmCode) {
|
||||
if (!pm.getNormalBasalManager().isSuspended()) {
|
||||
if (alarmCode != null) {
|
||||
pm.getPatchConfig().updateNormalBasalPausedSilently();
|
||||
}
|
||||
else {
|
||||
pm.getPatchConfig().updateNormalBasalPaused(pauseDurationHour);
|
||||
}
|
||||
pm.getNormalBasalManager().updateBasalSuspended();
|
||||
|
||||
pm.flushNormalBasalManager();
|
||||
pm.flushPatchConfig();
|
||||
|
||||
if((alarmCode == null || alarmCode.getType() == AlarmCode.TYPE_ALERT) && pauseDurationHour != 0)
|
||||
alarmRegistry.add(AlarmCode.B001, TimeUnit.MINUTES.toMillis((long)(pauseDurationHour * 60)), false).subscribe();
|
||||
}
|
||||
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
public synchronized void enqueue(float pauseDurationHour, long pausedTime, @Nullable AlarmCode alarmCode) {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = pause(pauseDurationHour, pausedTime, alarmCode)
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe(v -> {
|
||||
bolusCheckSubject.onNext(false);
|
||||
extendedBolusCheckSubject.onNext(false);
|
||||
basalCheckSubject.onNext(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.StartPriming;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.UpdateConnection;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
|
||||
@Singleton
|
||||
public class PrimingTask extends TaskBase {
|
||||
private final UpdateConnection UPDATE_CONNECTION;
|
||||
private final StartPriming START_PRIMING;
|
||||
|
||||
@Inject
|
||||
public PrimingTask() {
|
||||
super(TaskFunc.PRIMING);
|
||||
|
||||
UPDATE_CONNECTION = new UpdateConnection();
|
||||
START_PRIMING = new StartPriming();
|
||||
}
|
||||
|
||||
public Observable<Long> start(long count) {
|
||||
return isReady().concatMapSingle(v -> START_PRIMING.start())
|
||||
.doOnNext(this::checkResponse)
|
||||
.flatMap(v -> observePrimingSuccess(count))
|
||||
.takeUntil(value -> (value == count))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "PrimingTask error"));
|
||||
}
|
||||
|
||||
private Observable<Long> observePrimingSuccess(long count) {
|
||||
|
||||
return Observable.merge(
|
||||
Observable.interval(1, TimeUnit.SECONDS).take(count + 10)
|
||||
.map(v -> v * 3)
|
||||
.doOnNext(v -> {
|
||||
if (v >= count) {
|
||||
throw new Exception("Priming failed");
|
||||
}
|
||||
}),
|
||||
|
||||
Observable.interval(3, TimeUnit.SECONDS)
|
||||
.concatMapSingle(v -> UPDATE_CONNECTION.get())
|
||||
.map(response -> PatchState.Companion.create(response.getPatchState(), System.currentTimeMillis()))
|
||||
.filter(PatchState::isPrimingSuccess)
|
||||
.map(result -> count)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BolusFinishTimeGet;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusFinishTimeResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.code.BolusType;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.BolusCurrent;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class ReadBolusFinishTimeTask extends BolusTask {
|
||||
private final BolusFinishTimeGet BOLUS_FINISH_TIME_GET;
|
||||
|
||||
@Inject
|
||||
public ReadBolusFinishTimeTask() {
|
||||
super(TaskFunc.READ_BOLUS_FINISH_TIME);
|
||||
BOLUS_FINISH_TIME_GET = new BolusFinishTimeGet();
|
||||
}
|
||||
|
||||
Single<BolusFinishTimeResponse> read() {
|
||||
return isReady()
|
||||
.concatMapSingle(v -> BOLUS_FINISH_TIME_GET.get())
|
||||
.firstOrError()
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.doOnSuccess(this::onResponse)
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "ReadBolusFinishTimeTask error"));
|
||||
}
|
||||
|
||||
void onResponse(BolusFinishTimeResponse response) {
|
||||
PatchState patchState = pm.getPatchState();
|
||||
BolusCurrent bolusCurrent = pm.getBolusCurrent();
|
||||
long nowHistoryID = bolusCurrent.historyId(BolusType.NOW);
|
||||
long extHistoryID = bolusCurrent.historyId(BolusType.EXT);
|
||||
|
||||
if (nowHistoryID > 0 && patchState.isBolusDone(BolusType.NOW) && response.getNowBolusFinishTime() > 0) {
|
||||
bolusCurrent.setEndTimeSynced(BolusType.NOW, true);
|
||||
enqueue(TaskFunc.STOP_NOW_BOLUS);
|
||||
}
|
||||
|
||||
if (extHistoryID > 0 && patchState.isBolusDone(BolusType.EXT) && response.getExtBolusFinishTime() > 0) {
|
||||
bolusCurrent.setEndTimeSynced(BolusType.EXT, true);
|
||||
enqueue(TaskFunc.STOP_EXT_BOLUS);
|
||||
}
|
||||
|
||||
pm.flushBolusCurrent();
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = read()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.TempBasalFinishTimeGet;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TempBasalFinishTimeResponse;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class ReadTempBasalFinishTimeTask extends TaskBase {
|
||||
private final TempBasalFinishTimeGet TEMP_BASAL_FINISH_TIME_GET;
|
||||
|
||||
@Inject
|
||||
public ReadTempBasalFinishTimeTask() {
|
||||
super(TaskFunc.READ_TEMP_BASAL_FINISH_TIME);
|
||||
TEMP_BASAL_FINISH_TIME_GET = new TempBasalFinishTimeGet();
|
||||
}
|
||||
|
||||
public Single<TempBasalFinishTimeResponse> read() {
|
||||
return isReady()
|
||||
.concatMapSingle(v -> TEMP_BASAL_FINISH_TIME_GET.get())
|
||||
.firstOrError()
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.doOnSuccess(this::onResponse)
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "ReadTempBasalFinishTimeTask error"));
|
||||
}
|
||||
|
||||
private void onResponse(TempBasalFinishTimeResponse response) {
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = read()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.IAlarmRegistry;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.PatchStateManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BasalResume;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BaseResponse;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.NormalBasal;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class ResumeBasalTask extends TaskBase {
|
||||
@Inject IAlarmRegistry alarmRegistry;
|
||||
@Inject StartNormalBasalTask startNormalBasalTask;
|
||||
@Inject PatchStateManager patchStateManager;
|
||||
|
||||
private final BasalResume BASAL_RESUME;
|
||||
|
||||
@Inject
|
||||
public ResumeBasalTask() {
|
||||
super(TaskFunc.RESUME_BASAL);
|
||||
BASAL_RESUME = new BasalResume();
|
||||
}
|
||||
|
||||
public synchronized Single<? extends BaseResponse> resume() {
|
||||
if (pm.getPatchConfig().getNeedSetBasalSchedule()) {
|
||||
return startNormalBasalTask.start(pm.getNormalBasalManager().getNormalBasal());
|
||||
}
|
||||
|
||||
return isReady().concatMapSingle(v -> BASAL_RESUME.resume())
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.doOnSuccess(v -> onResumeResponse(v))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "ResumeBasalTask error"));
|
||||
}
|
||||
|
||||
private void onResumeResponse(PatchBooleanResponse v) {
|
||||
if (v.isSuccess()) {
|
||||
patchStateManager.onBasalResumed(v.getTimestamp() + 1000);
|
||||
alarmRegistry.remove(AlarmCode.B001).subscribe();
|
||||
}
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
checkPatchActivated();
|
||||
checkPatchConnected();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.PatchSelfTestResult;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetGlobalTime;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetTemperature;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetVoltageLevelB4Priming;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BatteryVoltageLevelPairingResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.GlobalTimeResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TemperatureResponse;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class SelfTestTask extends TaskBase {
|
||||
private final GetTemperature TEMPERATURE_GET;
|
||||
private final GetVoltageLevelB4Priming BATTERY_LEVEL_GET_BEFORE_PRIMING;
|
||||
private final GetGlobalTime GET_GLOBAL_TIME;
|
||||
|
||||
@Inject
|
||||
public SelfTestTask() {
|
||||
super(TaskFunc.SELF_TEST);
|
||||
|
||||
TEMPERATURE_GET = new GetTemperature();
|
||||
BATTERY_LEVEL_GET_BEFORE_PRIMING = new GetVoltageLevelB4Priming();
|
||||
GET_GLOBAL_TIME = new GetGlobalTime();
|
||||
}
|
||||
|
||||
public Single<PatchSelfTestResult> start() {
|
||||
Single<PatchSelfTestResult> tasks = Single.concat(Arrays.asList(
|
||||
TEMPERATURE_GET.get()
|
||||
.map(TemperatureResponse::getResult),
|
||||
BATTERY_LEVEL_GET_BEFORE_PRIMING.get()
|
||||
.map(BatteryVoltageLevelPairingResponse::getResult),
|
||||
GET_GLOBAL_TIME.get(false)
|
||||
.map(GlobalTimeResponse::getResult)))
|
||||
.filter(result -> result != PatchSelfTestResult.TEST_SUCCESS)
|
||||
.first(PatchSelfTestResult.TEST_SUCCESS);
|
||||
|
||||
return isReady()
|
||||
.concatMapSingle(v -> tasks)
|
||||
.firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "SelfTestTask error"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.GetGlobalTime;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.SetGlobalTime;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.GlobalTimeResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class SetGlobalTimeTask extends TaskBase {
|
||||
private final SetGlobalTime SET_GLOBAL_TIME;
|
||||
private final GetGlobalTime GET_GLOBAL_TIME;
|
||||
|
||||
@Inject
|
||||
public SetGlobalTimeTask() {
|
||||
super(TaskFunc.SET_GLOBAL_TIME);
|
||||
|
||||
SET_GLOBAL_TIME = new SetGlobalTime();
|
||||
GET_GLOBAL_TIME = new GetGlobalTime();
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> set() {
|
||||
return isReady()
|
||||
.concatMapSingle(v -> GET_GLOBAL_TIME.get(false))
|
||||
.doOnNext(this::checkResponse)
|
||||
.doOnNext(this::checkPatchTime)
|
||||
.concatMapSingle(v -> SET_GLOBAL_TIME.set())
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.doOnSuccess(v -> onSuccess())
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "SetGlobalTimeTask error"));
|
||||
}
|
||||
|
||||
private void checkPatchTime(GlobalTimeResponse response) throws Exception {
|
||||
|
||||
long newMilli = System.currentTimeMillis();
|
||||
long oldMilli = response.getGlobalTimeInMilli();
|
||||
long oldOffset = response.getTimeZoneOffset();
|
||||
int offset = TimeZone.getDefault().getOffset(newMilli);
|
||||
int minutes = (int) TimeUnit.MILLISECONDS.toMinutes(offset);
|
||||
int newOffset = minutes / 15;
|
||||
|
||||
long diff = Math.abs(oldMilli - newMilli);
|
||||
|
||||
if (diff > 60000 || oldOffset != newOffset) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, String.format("checkPatchTime %s %s %s", diff, oldOffset, newOffset));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception("No time set required");
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = set()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe(v -> {}, e -> {}); // Exception 을 사용하기에...
|
||||
}
|
||||
}
|
||||
|
||||
private void onSuccess() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.SetLowReservoirLevelAndExpireAlert;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class SetLowReservoirTask extends TaskBase {
|
||||
@Inject IPreferenceManager pm;
|
||||
|
||||
private final SetLowReservoirLevelAndExpireAlert SET_LOW_RESERVOIR_N_EXPIRE_ALERT;
|
||||
|
||||
@Inject
|
||||
public SetLowReservoirTask() {
|
||||
super(TaskFunc.LOW_RESERVOIR);
|
||||
SET_LOW_RESERVOIR_N_EXPIRE_ALERT = new SetLowReservoirLevelAndExpireAlert();
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> set(int doseUnit, int hours) {
|
||||
return isReady()
|
||||
.concatMapSingle(v -> SET_LOW_RESERVOIR_N_EXPIRE_ALERT.set(
|
||||
doseUnit,
|
||||
hours))
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "SetLowReservoirTask error"));
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
|
||||
int alertTime = pm.getPatchConfig().getPatchExpireAlertTime();
|
||||
int alertSetting = pm.getPatchConfig().getLowReservoirAlertAmount();
|
||||
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = set(alertSetting, alertTime)
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.StartBonding;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
import static info.nightscout.androidaps.plugins.pump.eopatch.core.api.StartBonding.OPTION_NUMERIC;
|
||||
|
||||
@Singleton
|
||||
public class StartBondTask extends TaskBase {
|
||||
private final StartBonding START_BOND;
|
||||
|
||||
@Inject
|
||||
public StartBondTask() {
|
||||
super(TaskFunc.START_BOND);
|
||||
START_BOND = new StartBonding();
|
||||
}
|
||||
|
||||
public Single<Boolean> start(String mac) {
|
||||
prefSetMacAddress(mac);
|
||||
patch.updateMacAddress(mac, false);
|
||||
|
||||
return isReady()
|
||||
.concatMapSingle(v -> START_BOND.start(OPTION_NUMERIC))
|
||||
.doOnNext(this::checkResponse)
|
||||
.concatMap(response -> patch.observeBondState())
|
||||
.doOnNext(state -> {
|
||||
if(state == BluetoothDevice.BOND_NONE) throw new Exception();
|
||||
})
|
||||
.filter(result -> result == BluetoothDevice.BOND_BONDED)
|
||||
.map(result -> true)
|
||||
.timeout(60, TimeUnit.SECONDS)
|
||||
.doOnNext(v -> prefSetMacAddress(mac))
|
||||
.doOnError(e -> {
|
||||
prefSetMacAddress("");
|
||||
aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StartBondTask error");
|
||||
})
|
||||
.firstOrError();
|
||||
}
|
||||
|
||||
private synchronized void prefSetMacAddress(String mac) {
|
||||
pm.getPatchConfig().setMacAddress(mac);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BolusStart;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusResponse;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class StartCalcBolusTask extends BolusTask {
|
||||
private final BolusStart NOW_BOLUS_START;
|
||||
|
||||
@Inject
|
||||
public StartCalcBolusTask() {
|
||||
super(TaskFunc.START_CALC_BOLUS);
|
||||
|
||||
NOW_BOLUS_START = new BolusStart();
|
||||
}
|
||||
|
||||
public Single<? extends BolusResponse> start(DetailedBolusInfo detailedBolusInfo) {
|
||||
return isReady().concatMapSingle(v -> startBolusImpl((float)detailedBolusInfo.insulin))
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.doOnSuccess(v -> onSuccess((float)detailedBolusInfo.insulin))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StartCalcBolusTask error"));
|
||||
}
|
||||
|
||||
private Single<? extends BolusResponse> startBolusImpl(float nowDoseU) {
|
||||
return NOW_BOLUS_START.start(nowDoseU);
|
||||
}
|
||||
|
||||
private void onSuccess(float nowDoseU) {
|
||||
onCalcBolusStarted(nowDoseU);
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.PatchStateManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BasalScheduleSetBig;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BasalScheduleSetResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.NormalBasal;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class StartNormalBasalTask extends TaskBase {
|
||||
private final BasalScheduleSetBig BASAL_SCHEDULE_SET_BIG;
|
||||
|
||||
@Inject PatchStateManager patchStateManager;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
|
||||
@Inject
|
||||
public StartNormalBasalTask() {
|
||||
super(TaskFunc.START_NORMAL_BASAL);
|
||||
BASAL_SCHEDULE_SET_BIG = new BasalScheduleSetBig();
|
||||
}
|
||||
|
||||
public Single<BasalScheduleSetResponse> start(NormalBasal basal) {
|
||||
return isReady().concatMapSingle(v -> startJob(basal)).firstOrError();
|
||||
}
|
||||
|
||||
public Single<BasalScheduleSetResponse> startJob(NormalBasal basal) {
|
||||
return BASAL_SCHEDULE_SET_BIG.set(basal.getDoseUnitPerSegmentArray())
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.doOnSuccess(v -> onStartNormalBasalResponse(v, basal))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StartNormalBasalTask error"));
|
||||
}
|
||||
|
||||
private void onStartNormalBasalResponse(BasalScheduleSetResponse response, NormalBasal basal) {
|
||||
|
||||
long timeStamp = response.getTimestamp();
|
||||
patchStateManager.onBasalStarted(basal, timeStamp+1000);
|
||||
|
||||
pm.getNormalBasalManager().setNormalBasal(basal);
|
||||
pm.flushNormalBasalManager();
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.code.BolusExDuration;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BolusStart;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.ComboBolusStart;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.ExtBolusStart;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusResponse;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class StartQuickBolusTask extends BolusTask {
|
||||
private final BolusStart NOW_BOLUS_START;
|
||||
private final ExtBolusStart EXT_BOLUS_START;
|
||||
private final ComboBolusStart COMBO_BOLUS_START;
|
||||
|
||||
@Inject
|
||||
public StartQuickBolusTask() {
|
||||
super(TaskFunc.START_QUICK_BOLUS);
|
||||
|
||||
NOW_BOLUS_START = new BolusStart();
|
||||
EXT_BOLUS_START = new ExtBolusStart();
|
||||
COMBO_BOLUS_START = new ComboBolusStart();
|
||||
}
|
||||
|
||||
public Single<? extends BolusResponse> start(float nowDoseU, float exDoseU,
|
||||
BolusExDuration exDuration) {
|
||||
return isReady().concatMapSingle(v -> startBolusImpl(nowDoseU, exDoseU, exDuration))
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.doOnSuccess(v -> onSuccess(nowDoseU, exDoseU, exDuration))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StartQuickBolusTask error"));
|
||||
}
|
||||
|
||||
private Single<? extends BolusResponse> startBolusImpl(float nowDoseU, float exDoseU,
|
||||
BolusExDuration exDuration) {
|
||||
if (nowDoseU > 0 && exDoseU > 0) {
|
||||
return COMBO_BOLUS_START.start(nowDoseU, exDoseU, exDuration.getMinute());
|
||||
} else if (exDoseU > 0) {
|
||||
return EXT_BOLUS_START.start(exDoseU, exDuration.getMinute());
|
||||
} else {
|
||||
return NOW_BOLUS_START.start(nowDoseU);
|
||||
}
|
||||
}
|
||||
|
||||
private void onSuccess(float nowDoseU, float exDoseU, BolusExDuration exDuration) {
|
||||
onQuickBolusStarted(nowDoseU, exDoseU, exDuration);
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
//checkPatchActivated();
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.TempBasalScheduleStart;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.TempBasalScheduleSetResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.TempBasal;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class StartTempBasalTask extends TaskBase {
|
||||
@Inject IPreferenceManager pm;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
|
||||
private final TempBasalScheduleStart TEMP_BASAL_SCHEDULE_START;
|
||||
|
||||
@Inject
|
||||
public StartTempBasalTask() {
|
||||
super(TaskFunc.START_TEMP_BASAL);
|
||||
|
||||
TEMP_BASAL_SCHEDULE_START = new TempBasalScheduleStart();
|
||||
}
|
||||
|
||||
public Single<TempBasalScheduleSetResponse> start(TempBasal tempBasal) {
|
||||
return isReady()
|
||||
.concatMapSingle(v -> TEMP_BASAL_SCHEDULE_START.start(tempBasal.getDurationMinutes(), tempBasal.getDoseUnitPerHour(), tempBasal.getPercent()))
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.doOnSuccess(v -> onTempBasalStarted(tempBasal))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StartTempBasalTask error"));
|
||||
}
|
||||
|
||||
private void onTempBasalStarted(TempBasal tempBasal) {
|
||||
pm.getTempBasalManager().updateBasalRunning(tempBasal);
|
||||
pm.flushTempBasalManager();
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import info.nightscout.androidaps.interfaces.PumpSync;
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger;
|
||||
import info.nightscout.androidaps.utils.userEntry.UserEntryMapper;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BasalStop;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BasalStopResponse;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.interfaces.CommandQueue;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.queue.commands.Command;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||
|
||||
@Singleton
|
||||
public class StopBasalTask extends TaskBase {
|
||||
@Inject IPreferenceManager pm;
|
||||
@Inject CommandQueue commandQueue;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject PumpSync pumpSync;
|
||||
@Inject UserEntryLogger uel;
|
||||
|
||||
private final BasalStop BASAL_STOP;
|
||||
private final BehaviorSubject<Boolean> bolusCheckSubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Boolean> exbolusCheckSubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Boolean> basalCheckSubject = BehaviorSubject.create();
|
||||
|
||||
@Inject
|
||||
public StopBasalTask() {
|
||||
super(TaskFunc.STOP_BASAL);
|
||||
|
||||
BASAL_STOP = new BasalStop();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getBolusSebject(){
|
||||
return bolusCheckSubject.hide();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getExbolusSebject(){
|
||||
return exbolusCheckSubject.hide();
|
||||
}
|
||||
|
||||
private Observable<Boolean> getBasalSebject(){
|
||||
return basalCheckSubject.hide();
|
||||
}
|
||||
|
||||
public Single<BasalStopResponse> stop() {
|
||||
|
||||
if (commandQueue.isRunning(Command.CommandType.BOLUS)) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_BOLUS, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelAllBoluses(null);
|
||||
SystemClock.sleep(650);
|
||||
}
|
||||
bolusCheckSubject.onNext(true);
|
||||
|
||||
if (pumpSync.expectedPumpState().getExtendedBolus() != null) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_EXTENDED_BOLUS, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelExtended(new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
exbolusCheckSubject.onNext(true);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
exbolusCheckSubject.onNext(true);
|
||||
}
|
||||
|
||||
if (pumpSync.expectedPumpState().getTemporaryBasal() != null) {
|
||||
uel.log(UserEntryMapper.Action.CANCEL_TEMP_BASAL, UserEntryMapper.Sources.EOPatch2);
|
||||
commandQueue.cancelTempBasal(true, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
basalCheckSubject.onNext(true);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
basalCheckSubject.onNext(true);
|
||||
}
|
||||
|
||||
return Observable.zip(getBolusSebject(), getExbolusSebject(), getBasalSebject(), (bolusReady, exbolusReady, basalReady)
|
||||
-> (bolusReady && exbolusReady && basalReady))
|
||||
.filter(ready -> ready)
|
||||
.flatMap(v -> isReady())
|
||||
.concatMapSingle(v -> BASAL_STOP.stop())
|
||||
.doOnNext(this::checkResponse)
|
||||
.firstOrError()
|
||||
.doOnSuccess(this::onBasalStopped)
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StopBasalTask error"));
|
||||
}
|
||||
|
||||
private void onBasalStopped(BasalStopResponse response) {
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = stop()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe(v -> {
|
||||
bolusCheckSubject.onNext(false);
|
||||
exbolusCheckSubject.onNext(false);
|
||||
basalCheckSubject.onNext(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.define.IPatchConstant;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.code.PatchBleResultCode;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BolusStop;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusStopResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.ComboBolusStopResponse;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class StopComboBolusTask extends BolusTask {
|
||||
private final BolusStop BOLUS_STOP;
|
||||
|
||||
@Inject
|
||||
public StopComboBolusTask() {
|
||||
super(TaskFunc.STOP_COMBO_BOLUS);
|
||||
BOLUS_STOP = new BolusStop();
|
||||
}
|
||||
|
||||
public Single<ComboBolusStopResponse> stop() {
|
||||
return isReady()
|
||||
.concatMapSingle(v -> stopJob())
|
||||
.firstOrError()
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.doOnSuccess(this::onComboBolusStopped)
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StopComboBolusTask error"));
|
||||
}
|
||||
|
||||
public Single<ComboBolusStopResponse> stopJob() {
|
||||
return Single.zip(
|
||||
BOLUS_STOP.stop(IPatchConstant.EXT_BOLUS_ID),
|
||||
BOLUS_STOP.stop(IPatchConstant.NOW_BOLUS_ID),
|
||||
(ext, now) -> createStopComboBolusResponse(now, ext));
|
||||
}
|
||||
|
||||
private ComboBolusStopResponse createStopComboBolusResponse(BolusStopResponse now, BolusStopResponse ext) {
|
||||
int idNow = now.isSuccess() ? IPatchConstant.NOW_BOLUS_ID : 0;
|
||||
int idExt = ext.isSuccess() ? IPatchConstant.EXT_BOLUS_ID : 0;
|
||||
|
||||
int injectedAmount = now.getInjectedBolusAmount();
|
||||
int injectingAmount = now.getInjectingBolusAmount();
|
||||
|
||||
int injectedExAmount = ext.getInjectedBolusAmount();
|
||||
int injectingExAmount = ext.getInjectingBolusAmount();
|
||||
|
||||
if (idNow == 0 && idExt == 0) {
|
||||
return new ComboBolusStopResponse(IPatchConstant.NOW_BOLUS_ID, PatchBleResultCode.BOLUS_UNKNOWN_ID);
|
||||
}
|
||||
|
||||
return new ComboBolusStopResponse(idNow, injectedAmount, injectingAmount, idExt, injectedExAmount, injectingExAmount);
|
||||
}
|
||||
|
||||
private void onComboBolusStopped(ComboBolusStopResponse response) {
|
||||
if (response.getId() != 0)
|
||||
updateNowBolusStopped(response.getInjectedBolusAmount());
|
||||
|
||||
if (response.getExtId() != 0)
|
||||
updateExtBolusStopped(response.getInjectedExBolusAmount());
|
||||
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = stop()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.define.IPatchConstant;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BolusStop;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusStopResponse;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class StopExtBolusTask extends BolusTask {
|
||||
private final BolusStop BOLUS_STOP;
|
||||
|
||||
@Inject
|
||||
public StopExtBolusTask() {
|
||||
super(TaskFunc.STOP_EXT_BOLUS);
|
||||
BOLUS_STOP = new BolusStop();
|
||||
}
|
||||
|
||||
public Single<BolusStopResponse> stop() {
|
||||
return isReady().concatMapSingle(v -> stopJob()).firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StopExtBolusTask error"));
|
||||
}
|
||||
|
||||
public Single<BolusStopResponse> stopJob() {
|
||||
return BOLUS_STOP.stop(IPatchConstant.EXT_BOLUS_ID)
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.doOnSuccess(this::onExtBolusStopped);
|
||||
}
|
||||
|
||||
|
||||
private void onExtBolusStopped(BolusStopResponse response) {
|
||||
updateExtBolusStopped(response.getInjectedBolusAmount());
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = stop()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
//checkPatchActivated();
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BolusStop;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.define.IPatchConstant;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BolusStopResponse;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class StopNowBolusTask extends BolusTask {
|
||||
private final BolusStop BOLUS_STOP;
|
||||
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
|
||||
@Inject
|
||||
public StopNowBolusTask() {
|
||||
super(TaskFunc.STOP_NOW_BOLUS);
|
||||
BOLUS_STOP = new BolusStop();
|
||||
}
|
||||
|
||||
public Single<BolusStopResponse> stop() {
|
||||
return isReady()
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.concatMapSingle(v -> stopJob()).firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StopNowBolusTask error"));
|
||||
}
|
||||
|
||||
public Single<BolusStopResponse> stopJob() {
|
||||
return BOLUS_STOP.stop(IPatchConstant.NOW_BOLUS_ID)
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.doOnSuccess(this::onNowBolusStopped);
|
||||
}
|
||||
|
||||
private void onNowBolusStopped(BolusStopResponse response) {
|
||||
updateNowBolusStopped(response.getInjectedBolusAmount());
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = stop()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.TempBasalScheduleStop;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.PatchBooleanResponse;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class StopTempBasalTask extends TaskBase {
|
||||
private final TempBasalScheduleStop TEMP_BASAL_SCHEDULE_STOP;
|
||||
|
||||
@Inject
|
||||
public StopTempBasalTask() {
|
||||
super(TaskFunc.STOP_TEMP_BASAL);
|
||||
|
||||
TEMP_BASAL_SCHEDULE_STOP = new TempBasalScheduleStop();
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> stop() {
|
||||
return isReady().concatMapSingle(v -> stopJob()).firstOrError()
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "StopTempBasalTask error"));
|
||||
}
|
||||
|
||||
public Single<PatchBooleanResponse> stopJob() {
|
||||
return TEMP_BASAL_SCHEDULE_STOP.stop()
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.doOnSuccess(v -> onTempBasalCanceled());
|
||||
}
|
||||
|
||||
private void onTempBasalCanceled() {
|
||||
enqueue(TaskFunc.UPDATE_CONNECTION);
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = stop()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preCondition() throws Exception {
|
||||
//checkPatchActivated();
|
||||
checkPatchConnected();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BasalHistoryGetExBig;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.BasalHistoryIndexGet;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.TempBasalHistoryGetExBig;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BasalHistoryIndexResponse;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BasalHistoryResponse;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
import static info.nightscout.androidaps.plugins.pump.eopatch.core.define.IPatchConstant.BASAL_HISTORY_SIZE_BIG;
|
||||
|
||||
@Singleton
|
||||
public class SyncBasalHistoryTask extends TaskBase {
|
||||
@Inject IPreferenceManager pm;
|
||||
|
||||
private final BasalHistoryIndexGet BASAL_HISTORY_INDEX_GET;
|
||||
private final BasalHistoryGetExBig BASAL_HISTORY_GET_EX_BIG;
|
||||
private final TempBasalHistoryGetExBig TEMP_BASAL_HISTORY_GET_EX_BIG;
|
||||
|
||||
@Inject
|
||||
public SyncBasalHistoryTask() {
|
||||
super(TaskFunc.SYNC_BASAL_HISTORY);
|
||||
|
||||
BASAL_HISTORY_INDEX_GET = new BasalHistoryIndexGet();
|
||||
BASAL_HISTORY_GET_EX_BIG = new BasalHistoryGetExBig();
|
||||
TEMP_BASAL_HISTORY_GET_EX_BIG = new TempBasalHistoryGetExBig();
|
||||
}
|
||||
|
||||
public Single<Integer> sync(int end) {
|
||||
return Single.just(1); // 베이젤 싱크 사용 안함
|
||||
}
|
||||
|
||||
public Single<Integer> sync() {
|
||||
return Single.just(1); // 베이젤 싱크 사용 안함
|
||||
}
|
||||
|
||||
private Single<Integer> getLastIndex() {
|
||||
return BASAL_HISTORY_INDEX_GET.get()
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.map(BasalHistoryIndexResponse::getLastFinishedIndex);
|
||||
}
|
||||
|
||||
private Single<Integer> syncBoth(int start, int end) {
|
||||
int count = end - start + 1;
|
||||
|
||||
if (count > 0) {
|
||||
return Single.zip(
|
||||
BASAL_HISTORY_GET_EX_BIG.get(start, count),
|
||||
TEMP_BASAL_HISTORY_GET_EX_BIG.get(start, count),
|
||||
(normal, temp) -> onBasalHistoryResponse(normal, temp, start, end));
|
||||
} else {
|
||||
return Single.just(-1);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void enqueue(int end) {
|
||||
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = sync(end)
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = sync()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private int onBasalHistoryResponse(BasalHistoryResponse n, BasalHistoryResponse t,
|
||||
int startRequested, int end) {
|
||||
|
||||
if (!n.isSuccess() || !t.isSuccess() || n.getSeq() != t.getSeq()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int start = n.getSeq();
|
||||
|
||||
float[] normal = n.getInjectedDoseValues();
|
||||
float[] temp = t.getInjectedDoseValues();
|
||||
|
||||
int count = Math.min(end - start + 1, BASAL_HISTORY_SIZE_BIG);
|
||||
count = Math.min(count, normal.length);
|
||||
count = Math.min(count, temp.length);
|
||||
|
||||
return updateInjected(normal, temp, start, end);
|
||||
}
|
||||
|
||||
public synchronized int updateInjected(float[] normal, float[] temp, int start, int end) {
|
||||
if (pm.getPatchState().isPatchInternalSuspended() && pm.getPatchConfig().isInBasalPausedTime() == false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lastUpdatedIndex = -1;
|
||||
int count = end - start + 1;
|
||||
|
||||
if (count > normal.length) {
|
||||
count = normal.length;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
int lastSyncIndex = pm.getPatchConfig().getLastIndex();
|
||||
for (int i = 0;i < count;i++) {
|
||||
int seq = start + i;
|
||||
if (seq < lastSyncIndex)
|
||||
continue;
|
||||
|
||||
if (start <= seq && seq <= end) {
|
||||
lastUpdatedIndex = seq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lastUpdatedIndex;
|
||||
}
|
||||
|
||||
private void updatePatchLastIndex(int newIndex) {
|
||||
int lastIndex = pm.getPatchConfig().getLastIndex();
|
||||
|
||||
if (lastIndex < newIndex) {
|
||||
pm.getPatchConfig().setLastIndex(newIndex);
|
||||
pm.flushPatchConfig();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.BleConnectionState;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.scan.IBleDevice;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.Patch;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.exception.NoActivatedPatchException;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.exception.PatchDisconnectedException;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.BaseResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
@Singleton
|
||||
public class TaskBase {
|
||||
protected IBleDevice patch;
|
||||
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject protected IPreferenceManager pm;
|
||||
@Inject TaskQueue taskQueue;
|
||||
|
||||
TaskFunc func;
|
||||
|
||||
static HashMap<TaskFunc, TaskBase> maps = new HashMap<>();
|
||||
|
||||
/* enqueue 시 사용 */
|
||||
protected Disposable disposable;
|
||||
|
||||
protected final Object lock = new Object();
|
||||
|
||||
protected static final long TASK_ENQUEUE_TIME_OUT = 60; // SECONDS
|
||||
|
||||
@Inject
|
||||
public TaskBase(TaskFunc func) {
|
||||
this.func = func;
|
||||
maps.put(func, this);
|
||||
patch = Patch.getInstance();
|
||||
}
|
||||
|
||||
/* Task 들의 작업 순서 및 조건 체크 */
|
||||
protected Observable<TaskFunc> isReady() {
|
||||
return taskQueue.isReady(func).doOnNext(v -> preCondition());
|
||||
}
|
||||
|
||||
protected Observable<TaskFunc> isReady2() {
|
||||
return taskQueue.isReady2(func).doOnNext(v -> preCondition());
|
||||
}
|
||||
|
||||
protected void checkResponse(BaseResponse response) throws Exception {
|
||||
if (!response.isSuccess()) {
|
||||
throw new Exception("Response failed! - "+response.resultCode.name());
|
||||
}
|
||||
}
|
||||
|
||||
public static void enqueue(TaskFunc func) {
|
||||
TaskBase task = maps.get(func);
|
||||
|
||||
if (task != null) {
|
||||
task.enqueue();
|
||||
}
|
||||
}
|
||||
|
||||
public static void enqueue(TaskFunc func, Boolean flag) {
|
||||
TaskBase task = maps.get(func);
|
||||
|
||||
if (task != null) {
|
||||
task.enqueue(flag);
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void enqueue() {
|
||||
}
|
||||
|
||||
protected synchronized void enqueue(Boolean flag) {
|
||||
}
|
||||
|
||||
protected void preCondition() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
protected void checkPatchConnected() throws Exception {
|
||||
if (patch.getConnectionState() == BleConnectionState.DISCONNECTED) {
|
||||
throw new PatchDisconnectedException();
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkPatchActivated() throws Exception {
|
||||
if (pm.getPatchConfig().isDeactivated()) {
|
||||
throw new NoActivatedPatchException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
public enum TaskFunc {
|
||||
START_BOND,
|
||||
GET_PATCH_INFO,
|
||||
SELF_TEST,
|
||||
PRIMING,
|
||||
NEEDLE_SENSING,
|
||||
ACTIVATE,
|
||||
DEACTIVATE,
|
||||
UPDATE_CONNECTION,
|
||||
START_NORMAL_BASAL,
|
||||
START_TEMP_BASAL,
|
||||
STOP_TEMP_BASAL,
|
||||
RESUME_BASAL,
|
||||
PAUSE_BASAL,
|
||||
STOP_BASAL,
|
||||
STOP_NOW_BOLUS,
|
||||
STOP_EXT_BOLUS,
|
||||
STOP_COMBO_BOLUS,
|
||||
START_QUICK_BOLUS,
|
||||
START_CALC_BOLUS,
|
||||
SYNC_BASAL_HISTORY,
|
||||
READ_BOLUS_FINISH_TIME,
|
||||
READ_TEMP_BASAL_FINISH_TIME,
|
||||
FETCH_ALARM,
|
||||
LOW_RESERVOIR,
|
||||
SET_GLOBAL_TIME,
|
||||
INFO_REMINDER,
|
||||
INTERNAL_SUSPEND
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||
|
||||
@Singleton
|
||||
public class TaskQueue {
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
|
||||
Queue<PatchTask> queue = new LinkedList<>();
|
||||
|
||||
private int sequence = 0;
|
||||
private final BehaviorSubject<PatchTask> ticketSubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Integer> sizeSubject = BehaviorSubject.createDefault(0);
|
||||
|
||||
@Inject
|
||||
public TaskQueue() {
|
||||
}
|
||||
|
||||
protected Observable<Integer> observeQueue() {
|
||||
return sizeSubject.distinctUntilChanged();
|
||||
}
|
||||
|
||||
protected synchronized Observable<TaskFunc> isReady(final TaskFunc function) {
|
||||
return Observable.fromCallable(() -> publishTicket(function))
|
||||
.concatMap(v -> ticketSubject
|
||||
.takeUntil(it -> it.number > v)
|
||||
.filter(it -> it.number == v))
|
||||
.doOnNext(v -> aapsLogger.debug(LTag.PUMPCOMM, String.format("Task #:%s started func:%s", v.number, v.func.name())))
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.map(it -> it.func)
|
||||
.doFinally(this::done);
|
||||
}
|
||||
|
||||
protected synchronized Observable<TaskFunc> isReady2(final TaskFunc function) {
|
||||
return observeQueue()
|
||||
.filter(size -> size == 0).concatMap(v -> isReady(function));
|
||||
}
|
||||
|
||||
private synchronized int publishTicket(final TaskFunc function) {
|
||||
int turn = sequence++;
|
||||
aapsLogger.debug(LTag.PUMPCOMM, String.format("publishTicket() Task #:%s is assigned func:%s", turn, function.name()));
|
||||
|
||||
PatchTask task = new PatchTask(turn, function);
|
||||
addQueue(task);
|
||||
return turn;
|
||||
}
|
||||
|
||||
private synchronized void addQueue(PatchTask task) {
|
||||
queue.add(task);
|
||||
int size = queue.size();
|
||||
sizeSubject.onNext(size);
|
||||
|
||||
if (size == 1) {
|
||||
ticketSubject.onNext(task);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void done() {
|
||||
if (queue.size() > 0) {
|
||||
PatchTask done = queue.remove();
|
||||
aapsLogger.debug(LTag.PUMPCOMM, String.format("done() Task #:%s completed func:%s task remaining:%s",
|
||||
done.number, done.func.name(), queue.size()));
|
||||
}
|
||||
|
||||
int size = queue.size();
|
||||
sizeSubject.onNext(size);
|
||||
|
||||
PatchTask next = queue.peek();
|
||||
if (next != null) {
|
||||
ticketSubject.onNext(next);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean has(TaskFunc func) {
|
||||
if (queue.size() > 1) {
|
||||
Iterator<PatchTask> iterator = queue.iterator();
|
||||
|
||||
/* remove 1st queue */
|
||||
iterator.next();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
PatchTask item = iterator.next();
|
||||
if (item.func == func) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static class PatchTask {
|
||||
|
||||
int number;
|
||||
TaskFunc func;
|
||||
|
||||
PatchTask(int number, TaskFunc func) {
|
||||
this.number = number;
|
||||
this.func = func;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.ble.task;
|
||||
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.PatchStateManager;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchState;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.api.UpdateConnection;
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.core.response.UpdateConnectionResponse;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
@Singleton
|
||||
public class UpdateConnectionTask extends TaskBase {
|
||||
@Inject PatchStateManager patchStateManager;
|
||||
|
||||
private UpdateConnection UPDATE_CONNECTION;
|
||||
|
||||
@Inject
|
||||
public UpdateConnectionTask() {
|
||||
super(TaskFunc.UPDATE_CONNECTION);
|
||||
|
||||
UPDATE_CONNECTION = new UpdateConnection();
|
||||
}
|
||||
|
||||
public Single<PatchState> update() {
|
||||
return isReady().concatMapSingle(v -> updateJob()).firstOrError();
|
||||
}
|
||||
|
||||
public Single<PatchState> updateJob() {
|
||||
return UPDATE_CONNECTION.get()
|
||||
.doOnSuccess(this::checkResponse)
|
||||
.map(UpdateConnectionResponse::getPatchState)
|
||||
.map(bytes -> PatchState.Companion.create(bytes, System.currentTimeMillis()))
|
||||
.doOnSuccess(state -> onUpdateConnection(state))
|
||||
.doOnError(e -> aapsLogger.error(LTag.PUMPCOMM, (e.getMessage() != null) ? e.getMessage() : "UpdateConnectionTask error"));
|
||||
}
|
||||
|
||||
private void onUpdateConnection(PatchState patchState) {
|
||||
patchStateManager.updatePatchState(patchState);
|
||||
}
|
||||
|
||||
public synchronized void enqueue() {
|
||||
boolean ready = (disposable == null || disposable.isDisposed());
|
||||
|
||||
if (ready) {
|
||||
disposable = update()
|
||||
.timeout(TASK_ENQUEUE_TIME_OUT, TimeUnit.SECONDS)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
enum class AlarmCategory{
|
||||
NONE,
|
||||
ALARM,
|
||||
ALERT;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
enum class BasalStatus constructor(val rawValue: Int) {
|
||||
STOPPED(0),
|
||||
PAUSED(1), //템프베이젤 주입중
|
||||
SUSPENDED(2), //주입 정지
|
||||
STARTED(3), //주입중
|
||||
SELECTED(4); //패치 폐기
|
||||
|
||||
val isStarted: Boolean
|
||||
get() = this == STARTED
|
||||
|
||||
val isSuspended: Boolean
|
||||
get() = this == SUSPENDED
|
||||
|
||||
val isStopped: Boolean
|
||||
get() = this == STOPPED
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun ofRaw(rawValue: Int?): BasalStatus {
|
||||
if (rawValue == null) {
|
||||
return STOPPED
|
||||
}
|
||||
|
||||
for (t in values()) {
|
||||
if (t.rawValue == rawValue) {
|
||||
return t
|
||||
}
|
||||
}
|
||||
return STOPPED
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
enum class BolusExDuration constructor(val index: Int, val minute: Int, val hour: Float) {
|
||||
OFF(0, 0, 0f),
|
||||
MINUTE_30(1, 30, 0.5f),
|
||||
MINUTE_60(2, 60, 1.0f),
|
||||
MINUTE_90(3, 90, 1.5f),
|
||||
MINUTE_120(4, 120, 2.0f),
|
||||
MINUTE_150(5, 150, 2.5f),
|
||||
MINUTE_180(6, 180, 3.0f),
|
||||
MINUTE_210(7, 210, 3.5f),
|
||||
MINUTE_240(8, 240, 4.0f),
|
||||
MINUTE_270(9, 270, 4.5f),
|
||||
MINUTE_300(10, 300, 5.0f),
|
||||
MINUTE_330(11, 330, 5.5f),
|
||||
MINUTE_360(12, 360, 6.0f),
|
||||
MINUTE_390(13, 390, 6.5f),
|
||||
MINUTE_420(14, 420, 7.0f),
|
||||
MINUTE_450(15, 450, 7.5f),
|
||||
MINUTE_480(16, 480, 8.0f);
|
||||
|
||||
fun milli(): Long {
|
||||
return TimeUnit.MINUTES.toMillis(this.minute.toLong())
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun ofRaw(rawValue: Int): BolusExDuration {
|
||||
for (t in values()) {
|
||||
if (t.minute == rawValue) {
|
||||
return t
|
||||
}
|
||||
}
|
||||
return OFF
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
|
||||
enum class DeactivationStatus {
|
||||
DEACTIVATION_FAILED,
|
||||
NORMAL_DEACTIVATED,
|
||||
FORCE_DEACTIVATED;
|
||||
|
||||
val isDeactivated: Boolean
|
||||
get() = this == NORMAL_DEACTIVATED || this == FORCE_DEACTIVATED
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun of(isSuccess: Boolean, forced: Boolean): DeactivationStatus {
|
||||
return when {
|
||||
isSuccess -> NORMAL_DEACTIVATED
|
||||
forced -> FORCE_DEACTIVATED
|
||||
else -> DEACTIVATION_FAILED
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
enum class EventType {
|
||||
ACTIVATION_CLICKED,
|
||||
DEACTIVATION_CLICKED,
|
||||
SUSPEND_CLICKED,
|
||||
RESUME_CLICKED,
|
||||
INVALID_BASAL_RATE,
|
||||
PROFILE_NOT_SET,
|
||||
SHOW_PATCH_COMM_DIALOG,
|
||||
DISMISS_PATCH_COMM_DIALOG,
|
||||
SHOW_PATCH_COMM_ERROR_DIALOG,
|
||||
SHOW_BONDED_DIALOG,
|
||||
SHOW_CHANGE_PATCH_DIALOG,
|
||||
FINISH_ACTIVITY,
|
||||
SHOW_DISCARD_DIALOG,
|
||||
PAUSE_BASAL_SUCCESS,
|
||||
PAUSE_BASAL_FAILED,
|
||||
RESUME_BASAL_SUCCESS,
|
||||
RESUME_BASAL_FAILED
|
||||
;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
enum class PatchExpireAlertTime constructor(val index: Int, val hour: Int) {
|
||||
HOUR_1(0, 1),
|
||||
HOUR_2(1, 2),
|
||||
HOUR_3(2, 3),
|
||||
HOUR_4(3, 4),
|
||||
HOUR_5(4, 5),
|
||||
HOUR_6(5, 6),
|
||||
HOUR_7(6, 7),
|
||||
HOUR_8(7, 8),
|
||||
HOUR_9(8, 9),
|
||||
HOUR_10(9, 10),
|
||||
HOUR_11(10, 11),
|
||||
HOUR_12(11, 12),
|
||||
HOUR_13(12, 13),
|
||||
HOUR_14(13, 14),
|
||||
HOUR_15(14, 15),
|
||||
HOUR_16(15, 16),
|
||||
HOUR_17(16, 17),
|
||||
HOUR_18(17, 18),
|
||||
HOUR_19(18, 19),
|
||||
HOUR_20(19, 20),
|
||||
HOUR_21(20, 21),
|
||||
HOUR_22(21, 22),
|
||||
HOUR_23(22, 23),
|
||||
HOUR_24(23, 24);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
enum class PatchLifecycle constructor(val rawValue: Int) {
|
||||
SHUTDOWN(1),
|
||||
BONDED(2),
|
||||
SAFETY_CHECK(3),
|
||||
REMOVE_NEEDLE_CAP(4),
|
||||
REMOVE_PROTECTION_TAPE(5),
|
||||
ROTATE_KNOB(6),
|
||||
BASAL_SETTING(7),
|
||||
ACTIVATED(8);
|
||||
|
||||
val isShutdown: Boolean
|
||||
get() = this == SHUTDOWN
|
||||
|
||||
val isActivated: Boolean
|
||||
get() = this == ACTIVATED
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
enum class PatchStep {
|
||||
SAFE_DEACTIVATION,
|
||||
MANUALLY_TURNING_OFF_ALARM,
|
||||
DISCARDED,
|
||||
DISCARDED_FOR_CHANGE,
|
||||
DISCARDED_FROM_ALARM,
|
||||
WAKE_UP,
|
||||
CONNECT_NEW,
|
||||
REMOVE_NEEDLE_CAP,
|
||||
REMOVE_PROTECTION_TAPE,
|
||||
SAFETY_CHECK,
|
||||
ROTATE_KNOB,
|
||||
ROTATE_KNOB_NEEDLE_INSERTION_ERROR,
|
||||
BASAL_SCHEDULE,
|
||||
SETTING_REMINDER_TIME,
|
||||
CHECK_CONNECTION,
|
||||
CANCEL,
|
||||
COMPLETE,
|
||||
BACK_TO_HOME,
|
||||
FINISH;
|
||||
|
||||
val isSafeDeactivation: Boolean
|
||||
get() = this == SAFE_DEACTIVATION
|
||||
|
||||
val isCheckConnection: Boolean
|
||||
get() = this == CHECK_CONNECTION
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.R
|
||||
|
||||
class SettingKeys {
|
||||
companion object{
|
||||
val LOW_RESERVOIR_REMINDERS: Int = R.string.key_eopatch_low_reservoir_reminders
|
||||
val EXPIRATION_REMINDERS: Int = R.string.key_eopatch_expiration_reminders
|
||||
val BUZZER_REMINDERS: Int = R.string.key_eopatch_patch_buzzer_reminders
|
||||
|
||||
val PATCH_CONFIG: Int = R.string.key_eopatch_patch_config
|
||||
val PATCH_STATE: Int = R.string.key_eopatch_patch_state
|
||||
val BOLUS_CURRENT: Int = R.string.key_eopatch_bolus_current
|
||||
val NORMAL_BASAL: Int = R.string.key_eopatch_normal_basal
|
||||
val TEMP_BASAL: Int = R.string.key_eopatch_temp_basal
|
||||
val ALARMS: Int = R.string.key_eopatch_bolus_current
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.code
|
||||
|
||||
enum class UnitOrPercent {
|
||||
P,
|
||||
U;
|
||||
|
||||
fun isPercentage() = this == P
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.dagger
|
||||
|
||||
import javax.inject.Qualifier
|
||||
import javax.inject.Scope
|
||||
|
||||
@Qualifier
|
||||
annotation class EopatchPluginQualifier
|
||||
|
||||
@MustBeDocumented
|
||||
@Scope
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class FragmentScope
|
|
@ -0,0 +1,139 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.dagger
|
||||
|
||||
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.OsAlarmReceiver
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmRegistry
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.IAlarmManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.IAlarmRegistry
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPatchManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.IPreferenceManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.PatchManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ble.PreferenceManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.*
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.dialogs.AlarmDialog
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.dialogs.ActivationNotCompleteDialog
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.dialogs.CommonDialog
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.viewmodel.EopatchOverviewViewModel
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.viewmodel.EopatchViewModel
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.viewmodel.ViewModelFactory
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.ui.viewmodel.ViewModelKey
|
||||
import javax.inject.Provider
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module(includes = [EopatchPrefModule::class])
|
||||
@Suppress("unused")
|
||||
abstract class EopatchModule {
|
||||
companion object {
|
||||
@Provides
|
||||
@EopatchPluginQualifier
|
||||
fun providesViewModelFactory(@EopatchPluginQualifier viewModels: MutableMap<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>): ViewModelProvider.Factory {
|
||||
return ViewModelFactory(viewModels)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindPatchManager(patchManager: PatchManager): IPatchManager
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindAlarmManager(alarmManager: AlarmManager): IAlarmManager
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindAlarmRegistry(alarmRegistry: AlarmRegistry): IAlarmRegistry
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindPreferenceManager(preferenceManager: PreferenceManager): IPreferenceManager
|
||||
|
||||
// #### VIEW MODELS ############################################################################
|
||||
@Binds
|
||||
@IntoMap
|
||||
@EopatchPluginQualifier
|
||||
@ViewModelKey(EopatchOverviewViewModel::class)
|
||||
internal abstract fun bindsEopatchOverviewViewmodel(viewModel: EopatchOverviewViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@EopatchPluginQualifier
|
||||
@ViewModelKey(EopatchViewModel::class)
|
||||
internal abstract fun bindsEopatchViewModel(viewModel: EopatchViewModel): ViewModel
|
||||
|
||||
// #### FRAGMENTS ##############################################################################
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchOverviewFragment(): EopatchOverviewFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchSafeDeactivationFragment(): EopatchSafeDeactivationFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchTurningOffAlarmFragment(): EopatchTurningOffAlarmFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchRemoveFragment(): EopatchRemoveFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchWakeUpFragment(): EopatchWakeUpFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchConnectNewFragment(): EopatchConnectNewFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchRemoveNeedleCapFragment(): EopatchRemoveNeedleCapFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchRemoveProtectionTapeFragment(): EopatchRemoveProtectionTapeFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchSafetyCheckFragment(): EopatchSafetyCheckFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchRotateKnobFragment(): EopatchRotateKnobFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesEopatchBasalScheduleFragment(): EopatchBasalScheduleFragment
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesAlarmDialog(): AlarmDialog
|
||||
|
||||
@FragmentScope
|
||||
@ContributesAndroidInjector
|
||||
internal abstract fun contributesCommonDialog(): ActivationNotCompleteDialog
|
||||
|
||||
// Activities
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesEopatchActivity(): EopatchActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesAlarmHelperActivity(): AlarmHelperActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesDialogHelperActivity(): DialogHelperActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesEoDialog(): CommonDialog
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesOsAlarmReceiver(): OsAlarmReceiver
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.dagger
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.Alarms
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.NormalBasalManager
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.PatchConfig
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.vo.TempBasalManager
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
class EopatchPrefModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun providePatchConfig(): PatchConfig {
|
||||
return PatchConfig()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun provideNormalBasalManager(): NormalBasalManager {
|
||||
return NormalBasalManager()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun provideTempBasalManager(): TempBasalManager {
|
||||
return TempBasalManager()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun provideAlarms(): Alarms {
|
||||
return Alarms()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.event
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.pump.eopatch.alarm.AlarmCode
|
||||
|
||||
class EventEoPatchAlarm(var alarmCodes: Set<AlarmCode>, var isFirst: Boolean = false) : Event()
|
||||
class EventDialog(val dialog: DialogFragment, val show: Boolean) : Event()
|
||||
class EventProgressDialog(val show: Boolean, @StringRes val resId: Int = 0) : Event()
|
||||
class EventPatchActivationNotComplete : Event()
|
|
@ -0,0 +1,19 @@
|
|||
package info.nightscout.androidaps.plugins.pump.eopatch.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()
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue