Initial bolus implementation, further connection improvements
This commit is contained in:
parent
a9ebdcfe68
commit
3027c2ffa5
12 changed files with 279 additions and 49 deletions
|
@ -27,6 +27,7 @@ dependencies {
|
||||||
implementation project(':core:main')
|
implementation project(':core:main')
|
||||||
implementation project(':core:ui')
|
implementation project(':core:ui')
|
||||||
implementation project(':core:validators')
|
implementation project(':core:validators')
|
||||||
|
implementation project(':pump:pump-common')
|
||||||
implementation project(':core:utils')
|
implementation project(':core:utils')
|
||||||
|
|
||||||
testImplementation project(':core:main')
|
testImplementation project(':core:main')
|
||||||
|
|
|
@ -8,12 +8,15 @@ import android.os.IBinder
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.core.ui.toast.ToastUtils
|
import info.nightscout.core.ui.toast.ToastUtils
|
||||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||||
|
import info.nightscout.interfaces.constraints.Constraint
|
||||||
|
import info.nightscout.interfaces.constraints.Constraints
|
||||||
import info.nightscout.interfaces.notifications.Notification
|
import info.nightscout.interfaces.notifications.Notification
|
||||||
import info.nightscout.interfaces.plugin.PluginDescription
|
import info.nightscout.interfaces.plugin.PluginDescription
|
||||||
import info.nightscout.interfaces.plugin.PluginType
|
import info.nightscout.interfaces.plugin.PluginType
|
||||||
import info.nightscout.interfaces.profile.Profile
|
import info.nightscout.interfaces.profile.Profile
|
||||||
import info.nightscout.interfaces.profile.ProfileFunction
|
import info.nightscout.interfaces.profile.ProfileFunction
|
||||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
||||||
|
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
|
||||||
import info.nightscout.interfaces.pump.Pump
|
import info.nightscout.interfaces.pump.Pump
|
||||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||||
import info.nightscout.interfaces.pump.PumpPluginBase
|
import info.nightscout.interfaces.pump.PumpPluginBase
|
||||||
|
@ -52,6 +55,7 @@ import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlin.math.abs
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
@Singleton class MedtrumPlugin @Inject constructor(
|
@Singleton class MedtrumPlugin @Inject constructor(
|
||||||
|
@ -59,6 +63,7 @@ import kotlin.math.round
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
rh: ResourceHelper,
|
rh: ResourceHelper,
|
||||||
commandQueue: CommandQueue,
|
commandQueue: CommandQueue,
|
||||||
|
private val constraintChecker: Constraints,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val aapsSchedulers: AapsSchedulers,
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
private val rxBus: RxBus,
|
private val rxBus: RxBus,
|
||||||
|
@ -69,6 +74,7 @@ import kotlin.math.round
|
||||||
private val uiInteraction: UiInteraction,
|
private val uiInteraction: UiInteraction,
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
private val pumpSync: PumpSync,
|
private val pumpSync: PumpSync,
|
||||||
|
private val detailedBolusInfoStorage: DetailedBolusInfoStorage,
|
||||||
private val temporaryBasalStorage: TemporaryBasalStorage
|
private val temporaryBasalStorage: TemporaryBasalStorage
|
||||||
) : PumpPluginBase(
|
) : PumpPluginBase(
|
||||||
PluginDescription()
|
PluginDescription()
|
||||||
|
@ -204,7 +210,7 @@ import kotlin.math.round
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lastDataTime(): Long {
|
override fun lastDataTime(): Long {
|
||||||
return medtrumPump.lastTimeReceivedFromPump * 1000L
|
return medtrumPump.lastTimeReceivedFromPump
|
||||||
}
|
}
|
||||||
|
|
||||||
override val baseBasalRate: Double
|
override val baseBasalRate: Double
|
||||||
|
@ -216,14 +222,46 @@ import kotlin.math.round
|
||||||
override val batteryLevel: Int
|
override val batteryLevel: Int
|
||||||
get() = 0 // TODO
|
get() = 0 // TODO
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||||
return PumpEnactResult(injector) // TODO
|
aapsLogger.debug(LTag.PUMP, "deliverTreatment: " + detailedBolusInfo.insulin + "U")
|
||||||
|
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
|
||||||
|
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value()
|
||||||
|
return if (detailedBolusInfo.insulin > 0 && detailedBolusInfo.carbs == 0.0) {
|
||||||
|
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Delivering bolus: " + detailedBolusInfo.insulin + "U")
|
||||||
|
detailedBolusInfoStorage.add(detailedBolusInfo) // will be picked up on reading history
|
||||||
|
val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.id)
|
||||||
|
val connectionOK = medtrumService?.setBolus(detailedBolusInfo.insulin, t) ?: false
|
||||||
|
val result = PumpEnactResult(injector)
|
||||||
|
result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep
|
||||||
|
result.bolusDelivered = t.insulin
|
||||||
|
if (!result.success) {
|
||||||
|
// Todo error code?
|
||||||
|
result.comment = "error"
|
||||||
|
} else {
|
||||||
|
result.comment = "ok"
|
||||||
|
}
|
||||||
|
aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Success: ${result.success} Asked: ${detailedBolusInfo.insulin} Delivered: ${result.bolusDelivered}")
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Invalid input")
|
||||||
|
val result = PumpEnactResult(injector)
|
||||||
|
result.success = false
|
||||||
|
result.bolusDelivered = 0.0
|
||||||
|
result.comment = rh.gs(info.nightscout.core.ui.R.string.invalid_input)
|
||||||
|
aapsLogger.error("deliverTreatment: Invalid input")
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stopBolusDelivering() {
|
override fun stopBolusDelivering() {
|
||||||
// TODO
|
if (!isInitialized()) return
|
||||||
|
|
||||||
|
aapsLogger.info(LTag.PUMP, "stopBolusDelivering")
|
||||||
|
medtrumService?.stopBolus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
|
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
|
||||||
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
|
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||||
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||||
import info.nightscout.pump.medtrum.extension.toInt
|
import info.nightscout.pump.medtrum.extension.toInt
|
||||||
|
import info.nightscout.rx.events.EventOverviewBolusProgress
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
|
@ -66,7 +67,15 @@ class MedtrumPump @Inject constructor(
|
||||||
set(value) {
|
set(value) {
|
||||||
_primeProgress.value = value
|
_primeProgress.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val _lastBasalRate = MutableStateFlow(0.0)
|
||||||
|
val lastBasalRateFlow: StateFlow<Double> = _lastBasalRate
|
||||||
|
var lastBasalRate: Double
|
||||||
|
get() = _lastBasalRate.value
|
||||||
|
set(value) {
|
||||||
|
_lastBasalRate.value = value
|
||||||
|
}
|
||||||
|
|
||||||
/** Stuff stored in SP */
|
/** Stuff stored in SP */
|
||||||
private var _patchSessionToken = 0L
|
private var _patchSessionToken = 0L
|
||||||
var patchSessionToken: Long
|
var patchSessionToken: Long
|
||||||
|
@ -136,9 +145,17 @@ class MedtrumPump @Inject constructor(
|
||||||
var alarmFlags = 0
|
var alarmFlags = 0
|
||||||
var alarmParameter = 0
|
var alarmParameter = 0
|
||||||
|
|
||||||
|
// bolus status
|
||||||
|
var bolusingTreatment: EventOverviewBolusProgress.Treatment? = null // actually delivered treatment
|
||||||
|
var bolusAmountToBeDelivered = 0.0 // amount to be delivered
|
||||||
|
var bolusProgressLastTimeStamp: Long = 0 // timestamp of last bolus progress message
|
||||||
|
var bolusStopped = false // bolus finished
|
||||||
|
var bolusStopForced = false // bolus forced to stop by user
|
||||||
|
var bolusDone = false // success end
|
||||||
|
|
||||||
// Last basal status update
|
// Last basal status update
|
||||||
// TODO: Save this in SP?
|
// TODO: Save this in SP?
|
||||||
var lastBasalRate = 0.0
|
|
||||||
var lastBasalSequence = 0
|
var lastBasalSequence = 0
|
||||||
var lastBasalPatchId = 0L
|
var lastBasalPatchId = 0L
|
||||||
var lastBasalStartTime = 0L
|
var lastBasalStartTime = 0L
|
||||||
|
@ -270,6 +287,17 @@ class MedtrumPump @Inject constructor(
|
||||||
handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now())
|
handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun handleBolusStatusUpdate(bolusType: Int, bolusCompleted: Boolean, amountDelivered: Double) {
|
||||||
|
aapsLogger.debug(LTag.PUMP, "handleBolusStatusUpdate: bolusType: $bolusType bolusCompleted: $bolusCompleted amountDelivered: $amountDelivered")
|
||||||
|
bolusProgressLastTimeStamp = dateUtil.now()
|
||||||
|
if (bolusCompleted) {
|
||||||
|
bolusDone = true
|
||||||
|
bolusingTreatment?.insulin = amountDelivered
|
||||||
|
} else {
|
||||||
|
bolusingTreatment?.insulin = amountDelivered
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun handleBasalStatusUpdate(basalType: BasalType, basalRate: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long, receivedTime: Long) {
|
fun handleBasalStatusUpdate(basalType: BasalType, basalRate: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long, receivedTime: Long) {
|
||||||
aapsLogger.debug(
|
aapsLogger.debug(
|
||||||
LTag.PUMP,
|
LTag.PUMP,
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package info.nightscout.pump.medtrum.comm.enums
|
||||||
|
|
||||||
|
enum class BolusType {
|
||||||
|
NONE,
|
||||||
|
NORMAL,
|
||||||
|
EXTEND,
|
||||||
|
COMBINATION;
|
||||||
|
|
||||||
|
fun getValue(): Int {
|
||||||
|
return ordinal
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,14 +41,6 @@ class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleResponse(data: ByteArray): Boolean {
|
override fun handleResponse(data: ByteArray): Boolean {
|
||||||
if (data.size > 3) {
|
|
||||||
val incomingOpCode: Byte = data.copyOfRange(RESP_OPCODE_START, RESP_OPCODE_END).first()
|
|
||||||
if (incomingOpCode == CommandType.SUBSCRIBE.code) {
|
|
||||||
// TODO: Test and see if this can be removed
|
|
||||||
aapsLogger.error(LTag.PUMPCOMM, "handleResponse: Got subscribe response instead of authorize response, handling subscribe packet")
|
|
||||||
return SubscribePacket(injector).handleResponse(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val success = super.handleResponse(data)
|
val success = super.handleResponse(data)
|
||||||
if (success) {
|
if (success) {
|
||||||
deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
|
deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package info.nightscout.pump.medtrum.comm.packets
|
package info.nightscout.pump.medtrum.comm.packets
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
|
||||||
import info.nightscout.interfaces.pump.PumpSync
|
import info.nightscout.interfaces.pump.PumpSync
|
||||||
import info.nightscout.interfaces.pump.TemporaryBasalStorage
|
import info.nightscout.interfaces.pump.TemporaryBasalStorage
|
||||||
import info.nightscout.pump.medtrum.MedtrumPump
|
import info.nightscout.pump.medtrum.MedtrumPump
|
||||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD
|
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD
|
||||||
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||||
|
import info.nightscout.pump.medtrum.comm.enums.BolusType
|
||||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||||
import info.nightscout.pump.medtrum.extension.toInt
|
import info.nightscout.pump.medtrum.extension.toInt
|
||||||
import info.nightscout.pump.medtrum.extension.toLong
|
import info.nightscout.pump.medtrum.extension.toLong
|
||||||
|
@ -20,6 +22,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
|
||||||
@Inject lateinit var medtrumPump: MedtrumPump
|
@Inject lateinit var medtrumPump: MedtrumPump
|
||||||
@Inject lateinit var pumpSync: PumpSync
|
@Inject lateinit var pumpSync: PumpSync
|
||||||
@Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
|
@Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
|
||||||
|
@Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -85,6 +88,51 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
|
||||||
when (recordType) {
|
when (recordType) {
|
||||||
BOLUS_RECORD, BOLUS_RECORD_ALT -> {
|
BOLUS_RECORD, BOLUS_RECORD_ALT -> {
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD")
|
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD")
|
||||||
|
val typeAndWizard = data.copyOfRange(RESP_RECORD_DATA_START, RESP_RECORD_DATA_START + 1).toInt()
|
||||||
|
val bolusCause = data.copyOfRange(RESP_RECORD_DATA_START + 1, RESP_RECORD_DATA_START + 2).toInt()
|
||||||
|
val unknown = data.copyOfRange(RESP_RECORD_DATA_START + 2, RESP_RECORD_DATA_START + 4).toInt()
|
||||||
|
val bolusStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START + 4, RESP_RECORD_DATA_START + 8).toLong())
|
||||||
|
val bolusNormalAmount = data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 10).toInt() * 0.05
|
||||||
|
val bolusNormalDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 10, RESP_RECORD_DATA_START + 12).toInt() * 0.05
|
||||||
|
val bolusExtendedAmount = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 14).toInt() * 0.05
|
||||||
|
val bolusExtendedDuration = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toInt()
|
||||||
|
val bolusExtendedDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 16, RESP_RECORD_DATA_START + 18).toInt() * 0.05
|
||||||
|
val bolusCarb = data.copyOfRange(RESP_RECORD_DATA_START + 18, RESP_RECORD_DATA_START + 20).toInt()
|
||||||
|
val bolusGlucose = data.copyOfRange(RESP_RECORD_DATA_START + 20, RESP_RECORD_DATA_START + 22).toInt()
|
||||||
|
val bolusIOB = data.copyOfRange(RESP_RECORD_DATA_START + 22, RESP_RECORD_DATA_START + 24).toInt()
|
||||||
|
val unkown1 = data.copyOfRange(RESP_RECORD_DATA_START + 24, RESP_RECORD_DATA_START + 26).toInt()
|
||||||
|
val unkown2 = data.copyOfRange(RESP_RECORD_DATA_START + 26, RESP_RECORD_DATA_START + 28).toInt()
|
||||||
|
val bolusType = enumValues<BolusType>()[typeAndWizard and 0x0F]
|
||||||
|
val bolusWizard = (typeAndWizard and 0xF0) != 0
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMPCOMM,
|
||||||
|
"GetRecordPacket HandleResponse: BOLUS_RECORD: typeAndWizard: $typeAndWizard, bolusCause: $bolusCause, unknown: $unknown, bolusStartTime: $bolusStartTime, " + "bolusNormalAmount: $bolusNormalAmount, bolusNormalDelivered: $bolusNormalDelivered, bolusExtendedAmount: $bolusExtendedAmount, bolusExtendedDuration: $bolusExtendedDuration, " + "bolusExtendedDelivered: $bolusExtendedDelivered, bolusCarb: $bolusCarb, bolusGlucose: $bolusGlucose, bolusIOB: $bolusIOB, unkown1: $unkown1, unkown2: $unkown2, " + "bolusType: $bolusType, bolusWizard: $bolusWizard"
|
||||||
|
)
|
||||||
|
if (bolusType == BolusType.NORMAL) {
|
||||||
|
val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(bolusStartTime, bolusNormalDelivered)
|
||||||
|
val newRecord = pumpSync.syncBolusWithPumpId(
|
||||||
|
timestamp = bolusStartTime,
|
||||||
|
amount = bolusNormalDelivered,
|
||||||
|
type = detailedBolusInfo?.bolusType,
|
||||||
|
pumpId = bolusStartTime,
|
||||||
|
pumpType = medtrumPump.pumpType,
|
||||||
|
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||||
|
)
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMPCOMM,
|
||||||
|
"from record: ${if (newRecord) "**NEW** " else ""}EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U "
|
||||||
|
)
|
||||||
|
if (!newRecord && detailedBolusInfo != null) {
|
||||||
|
// detailedInfo can be from another similar record. Reinsert
|
||||||
|
detailedBolusInfoStorage.add(detailedBolusInfo)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aapsLogger.error(
|
||||||
|
LTag.PUMPCOMM,
|
||||||
|
"from record: EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) " + "Bolus type: $bolusType not supported"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BASAL_RECORD, BASAL_RECORD_ALT -> {
|
BASAL_RECORD, BASAL_RECORD_ALT -> {
|
||||||
|
|
|
@ -98,13 +98,10 @@ class NotificationPacket(val injector: HasAndroidInjector) {
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
|
aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
|
||||||
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
|
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
|
||||||
var bolusType = bolusData and 0x7F
|
var bolusType = bolusData and 0x7F
|
||||||
var bolusCompleted = (bolusData shr 7) and 0x01 // TODO: Check for other flags here :)
|
val bolusCompleted: Boolean = ((bolusData shr 7) and 0x01) != 0 // TODO: Check for other flags here :)
|
||||||
var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() * 0.05
|
var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() * 0.05
|
||||||
// TODO Sync bolus flow:
|
|
||||||
// If bolus is known add status
|
|
||||||
// If bolus is not known start read bolus
|
|
||||||
// When bolus is completed, remove bolus from medtrumPump
|
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolusData: $bolusData bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
|
aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolusData: $bolusData bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
|
||||||
|
medtrumPump.handleBolusStatusUpdate(bolusType, bolusCompleted, bolusDelivered)
|
||||||
offset += 3
|
offset += 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,8 +90,8 @@ class BLEComm @Inject internal constructor(
|
||||||
private val mBluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
|
private val mBluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
|
||||||
private var mBluetoothGatt: BluetoothGatt? = null
|
private var mBluetoothGatt: BluetoothGatt? = null
|
||||||
|
|
||||||
var isConnected = false // TODO: These may be removed have no function
|
private var isConnected = false // Only to track internal ble state
|
||||||
var isConnecting = false// TODO: These may be removed have no function
|
private var isConnecting = false // Only to track internal ble state
|
||||||
private var uartWrite: BluetoothGattCharacteristic? = null
|
private var uartWrite: BluetoothGattCharacteristic? = null
|
||||||
private var uartRead: BluetoothGattCharacteristic? = null
|
private var uartRead: BluetoothGattCharacteristic? = null
|
||||||
|
|
||||||
|
@ -126,14 +126,12 @@ class BLEComm @Inject internal constructor(
|
||||||
|
|
||||||
|
|
||||||
isConnected = false
|
isConnected = false
|
||||||
// TODO: Maybe replace this by (or add) a isScanning parameter?
|
|
||||||
isConnecting = true
|
isConnecting = true
|
||||||
|
|
||||||
// Find our Medtrum Device!
|
// Find our Medtrum Device!
|
||||||
filters.add(
|
filters.add(
|
||||||
ScanFilter.Builder().setDeviceName("MT").build()
|
ScanFilter.Builder().setDeviceName("MT").build()
|
||||||
)
|
)
|
||||||
// TODO Check if we need to add MAC for reconnects? Not sure if otherwise we can find the device
|
|
||||||
mBluetoothAdapter?.bluetoothLeScanner?.startScan(filters, settings, mScanCallback)
|
mBluetoothAdapter?.bluetoothLeScanner?.startScan(filters, settings, mScanCallback)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -159,6 +157,9 @@ class BLEComm @Inject internal constructor(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: THIS IS A WORKAROUND TEST
|
||||||
|
mWritePackets = WriteCommandPackets()
|
||||||
|
|
||||||
if (mDevice != null && mDeviceSN == deviceSN) {
|
if (mDevice != null && mDeviceSN == deviceSN) {
|
||||||
// Skip scanning and directly connect to gatt
|
// Skip scanning and directly connect to gatt
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Skipping scan and directly connecting to gatt")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Skipping scan and directly connecting to gatt")
|
||||||
|
@ -178,7 +179,7 @@ class BLEComm @Inject internal constructor(
|
||||||
/** Connect flow: 2. When device is found this is called by onScanResult() */
|
/** Connect flow: 2. When device is found this is called by onScanResult() */
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun connectGatt(device: BluetoothDevice) {
|
private fun connectGatt(device: BluetoothDevice) {
|
||||||
mBluetoothGatt =
|
mBluetoothGatt =
|
||||||
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
|
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
|
||||||
}
|
}
|
||||||
|
@ -196,12 +197,14 @@ class BLEComm @Inject internal constructor(
|
||||||
if (isConnecting) {
|
if (isConnecting) {
|
||||||
stopScan()
|
stopScan()
|
||||||
}
|
}
|
||||||
mBluetoothGatt?.disconnect()
|
if (isConnected) {
|
||||||
}
|
mBluetoothGatt?.disconnect()
|
||||||
|
} else {
|
||||||
@Synchronized
|
close()
|
||||||
fun stopConnecting() {
|
isConnected = false
|
||||||
isConnecting = false
|
isConnecting = false
|
||||||
|
mCallback?.onBLEDisconnected()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
|
@ -347,8 +350,6 @@ class BLEComm @Inject internal constructor(
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Notifications enabled!")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Notifications enabled!")
|
||||||
/** Connect flow: 6. Connected */
|
/** Connect flow: 6. Connected */
|
||||||
mCallback?.onBLEConnected()
|
mCallback?.onBLEConnected()
|
||||||
isConnected = true
|
|
||||||
isConnecting = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -384,9 +385,9 @@ class BLEComm @Inject internal constructor(
|
||||||
private fun onConnectionStateChangeSynchronized(gatt: BluetoothGatt, status: Int, newState: Int) {
|
private fun onConnectionStateChangeSynchronized(gatt: BluetoothGatt, status: Int, newState: Int) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange newState: " + newState + " status: " + status)
|
aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange newState: " + newState + " status: " + status)
|
||||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||||
handler.postDelayed({
|
isConnected = true
|
||||||
mBluetoothGatt?.discoverServices()
|
isConnecting = false
|
||||||
}, WRITE_DELAY_MILLIS)
|
mBluetoothGatt?.discoverServices()
|
||||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||||
close()
|
close()
|
||||||
isConnected = false
|
isConnected = false
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.os.SystemClock
|
||||||
import dagger.android.DaggerService
|
import dagger.android.DaggerService
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||||
|
@ -14,6 +15,7 @@ import info.nightscout.interfaces.profile.Profile
|
||||||
import info.nightscout.interfaces.profile.ProfileFunction
|
import info.nightscout.interfaces.profile.ProfileFunction
|
||||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||||
import info.nightscout.interfaces.pump.PumpSync
|
import info.nightscout.interfaces.pump.PumpSync
|
||||||
|
import info.nightscout.interfaces.queue.Callback
|
||||||
import info.nightscout.interfaces.queue.CommandQueue
|
import info.nightscout.interfaces.queue.CommandQueue
|
||||||
import info.nightscout.interfaces.ui.UiInteraction
|
import info.nightscout.interfaces.ui.UiInteraction
|
||||||
import info.nightscout.pump.medtrum.MedtrumPlugin
|
import info.nightscout.pump.medtrum.MedtrumPlugin
|
||||||
|
@ -42,6 +44,7 @@ import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.round
|
||||||
|
|
||||||
class MedtrumService : DaggerService(), BLECommCallback {
|
class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
|
|
||||||
|
@ -130,12 +133,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopConnecting() {
|
fun stopConnecting() {
|
||||||
// TODO proper way for this might need send commands etc
|
bleComm.disconnect("stopConnecting")
|
||||||
bleComm.stopConnecting()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disconnect(from: String) {
|
fun disconnect(from: String) {
|
||||||
// TODO proper way for this might need send commands etc
|
|
||||||
bleComm.disconnect(from)
|
bleComm.disconnect(from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,14 +156,58 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean {
|
fun setBolus(insulin: Double, t: EventOverviewBolusProgress.Treatment): Boolean {
|
||||||
if (!isConnected) return false
|
if (!isConnected) return false
|
||||||
// TODO
|
val result = sendPacketAndGetResponse(SetBolusPacket(injector, insulin))
|
||||||
return false
|
|
||||||
|
medtrumPump.bolusDone = false
|
||||||
|
medtrumPump.bolusingTreatment = t
|
||||||
|
medtrumPump.bolusAmountToBeDelivered = insulin
|
||||||
|
medtrumPump.bolusStopped = false
|
||||||
|
medtrumPump.bolusStopForced = false
|
||||||
|
medtrumPump.bolusProgressLastTimeStamp = dateUtil.now()
|
||||||
|
|
||||||
|
val bolusStart = System.currentTimeMillis()
|
||||||
|
|
||||||
|
val bolusingEvent = EventOverviewBolusProgress
|
||||||
|
while (medtrumPump.bolusStopped == false && result == true && medtrumPump.bolusDone == false) {
|
||||||
|
SystemClock.sleep(100)
|
||||||
|
if (System.currentTimeMillis() - medtrumPump.bolusProgressLastTimeStamp > T.secs(15).msecs()) {
|
||||||
|
medtrumPump.bolusStopped = true
|
||||||
|
medtrumPump.bolusStopForced = true
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "Communication stopped")
|
||||||
|
bleComm.disconnect("Communication stopped")
|
||||||
|
} else {
|
||||||
|
bolusingEvent.t = medtrumPump.bolusingTreatment
|
||||||
|
bolusingEvent.status = rh.gs(info.nightscout.pump.common.R.string.bolus_delivered_so_far, medtrumPump.bolusingTreatment?.insulin, medtrumPump.bolusAmountToBeDelivered)
|
||||||
|
bolusingEvent.percent = round((medtrumPump.bolusingTreatment?.insulin?.div(medtrumPump.bolusAmountToBeDelivered) ?: 0.0) * 100).toInt() - 1
|
||||||
|
rxBus.send(bolusingEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bolusingEvent.t = medtrumPump.bolusingTreatment
|
||||||
|
bolusingEvent.percent = 99
|
||||||
|
medtrumPump.bolusingTreatment = null
|
||||||
|
|
||||||
|
val bolusDurationInMSec = (insulin * 60 * 1000)
|
||||||
|
val expectedEnd = bolusStart + bolusDurationInMSec + 2000
|
||||||
|
while (System.currentTimeMillis() < expectedEnd) {
|
||||||
|
SystemClock.sleep(1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not call update status directly, reconnection may be needed
|
||||||
|
commandQueue.readStatus(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus), object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus)))
|
||||||
|
bolusingEvent.percent = 100
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bolusStop() {
|
fun stopBolus() {
|
||||||
// TODO
|
var result = sendPacketAndGetResponse(CancelBolusPacket(injector))
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "bolusStop: result: $result")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setTempBasal(absoluteRate: Double, durationInMinutes: Int): Boolean {
|
fun setTempBasal(absoluteRate: Double, durationInMinutes: Int): Boolean {
|
||||||
|
@ -190,12 +235,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateBasalsInPump(profile: Profile): Boolean {
|
fun updateBasalsInPump(profile: Profile): Boolean {
|
||||||
var result = false
|
var result = true
|
||||||
val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
|
|
||||||
result = packet?.let { sendPacketAndGetResponse(it) } == true
|
|
||||||
|
|
||||||
// TODO: We might want to get rid of this and cancel the TBR before we set the basal profile
|
|
||||||
// Update basal affects the TBR records (the pump will cancel the TBR, set our basal profile, and resume the TBR in a new record)
|
// Update basal affects the TBR records (the pump will cancel the TBR, set our basal profile, and resume the TBR in a new record)
|
||||||
|
// Cancel any TBR in progress
|
||||||
|
if (medtrumPump.tempBasalInProgress) {
|
||||||
|
result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
|
||||||
|
}
|
||||||
|
val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
|
||||||
|
if (result) result = packet?.let { sendPacketAndGetResponse(it) } == true
|
||||||
|
|
||||||
// Get history records, this will update the pump state and add changes in TBR to AAPS history
|
// Get history records, this will update the pump state and add changes in TBR to AAPS history
|
||||||
if (result) result = syncRecords()
|
if (result) result = syncRecords()
|
||||||
|
|
||||||
|
@ -211,7 +259,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
||||||
private fun syncRecords(): Boolean {
|
private fun syncRecords(): Boolean {
|
||||||
aapsLogger.debug(LTag.PUMP, "syncRecords: called!, syncedSequenceNumber: ${medtrumPump.syncedSequenceNumber}, currentSequenceNumber: ${medtrumPump.currentSequenceNumber}")
|
aapsLogger.debug(LTag.PUMP, "syncRecords: called!, syncedSequenceNumber: ${medtrumPump.syncedSequenceNumber}, currentSequenceNumber: ${medtrumPump.currentSequenceNumber}")
|
||||||
var result = false
|
var result = false
|
||||||
// TODO: Check if we need to sync older records as well
|
|
||||||
// Note: medtrum app fetches all records when they sync?
|
// Note: medtrum app fetches all records when they sync?
|
||||||
for (sequence in medtrumPump.syncedSequenceNumber..medtrumPump.currentSequenceNumber) {
|
for (sequence in medtrumPump.syncedSequenceNumber..medtrumPump.currentSequenceNumber) {
|
||||||
result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
|
result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
|
||||||
|
|
|
@ -10,6 +10,7 @@ import info.nightscout.pump.medtrum.ui.event.UIEvent
|
||||||
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
|
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
|
||||||
import info.nightscout.interfaces.profile.ProfileFunction
|
import info.nightscout.interfaces.profile.ProfileFunction
|
||||||
import info.nightscout.pump.medtrum.MedtrumPump
|
import info.nightscout.pump.medtrum.MedtrumPump
|
||||||
|
import info.nightscout.pump.medtrum.R
|
||||||
import info.nightscout.pump.medtrum.code.ConnectionState
|
import info.nightscout.pump.medtrum.code.ConnectionState
|
||||||
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
|
@ -17,6 +18,7 @@ import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventPumpStatusChanged
|
import info.nightscout.rx.events.EventPumpStatusChanged
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
@ -27,6 +29,7 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class MedtrumOverviewViewModel @Inject constructor(
|
class MedtrumOverviewViewModel @Inject constructor(
|
||||||
private val aapsLogger: AAPSLogger,
|
private val aapsLogger: AAPSLogger,
|
||||||
|
private val rh: ResourceHelper,
|
||||||
private val rxBus: RxBus,
|
private val rxBus: RxBus,
|
||||||
private val aapsSchedulers: AapsSchedulers,
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
private val fabricPrivacy: FabricPrivacy,
|
private val fabricPrivacy: FabricPrivacy,
|
||||||
|
@ -48,6 +51,10 @@ class MedtrumOverviewViewModel @Inject constructor(
|
||||||
val isPatchActivated: LiveData<Boolean>
|
val isPatchActivated: LiveData<Boolean>
|
||||||
get() = _isPatchActivated
|
get() = _isPatchActivated
|
||||||
|
|
||||||
|
private val _runningBasalRate = SingleLiveEvent<String>()
|
||||||
|
val runningBasalRate: LiveData<String>
|
||||||
|
get() = _runningBasalRate
|
||||||
|
|
||||||
init {
|
init {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
medtrumPump.connectionStateFlow.collect { state ->
|
medtrumPump.connectionStateFlow.collect { state ->
|
||||||
|
@ -77,6 +84,12 @@ class MedtrumOverviewViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
scope.launch {
|
||||||
|
medtrumPump.lastBasalRateFlow.collect { rate ->
|
||||||
|
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel runningBasalRateFlow: $rate")
|
||||||
|
_runningBasalRate.postValue(String.format(rh.gs(R.string.current_basal_rate), rate))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
|
|
|
@ -91,6 +91,54 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="2dip"
|
||||||
|
android:layout_marginLeft="20dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:background="@color/list_delimiter" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginVertical="3dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.5"
|
||||||
|
android:gravity="end"
|
||||||
|
android:paddingStart="5dp"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:text="@string/current_basal_label"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="5dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
|
android:text="@string/colon"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/current_basal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="start"
|
||||||
|
android:paddingStart="5dp"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:text="@{viewmodel.runningBasalRate}"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -12,12 +12,14 @@
|
||||||
<string name="key_synced_sequence_number" translatable="false">synced_sequence_number</string>
|
<string name="key_synced_sequence_number" translatable="false">synced_sequence_number</string>
|
||||||
|
|
||||||
<string name="medtrum">Medtrum</string>
|
<string name="medtrum">Medtrum</string>
|
||||||
<string name="medtrum_pump_shortname">MEDTRUM</string>
|
<string name="medtrum_pump_shortname">MT</string>
|
||||||
<string name="medtrum_pump_description">Medtrum Nano</string>
|
<string name="medtrum_pump_description">Medtrum Nano</string>
|
||||||
<string name="medtrumpump_settings">Medtrum pump settings</string>
|
<string name="medtrumpump_settings">Medtrum pump settings</string>
|
||||||
|
|
||||||
<!-- overview fragment -->
|
<!-- overview fragment -->
|
||||||
<string name="medtrum_ble_status">BLE Status</string>
|
<string name="medtrum_ble_status">BLE Status</string>
|
||||||
|
<string name="current_basal_label">Active basal</string>
|
||||||
|
<string name="current_basal_rate"> %.2f U/h</string>
|
||||||
<string name="string_new_patch">Start new patch</string>
|
<string name="string_new_patch">Start new patch</string>
|
||||||
<string name="string_stop_patch">Stop patch</string>
|
<string name="string_stop_patch">Stop patch</string>
|
||||||
|
|
||||||
|
@ -40,5 +42,8 @@
|
||||||
<string name="snInput_title">SN</string>
|
<string name="snInput_title">SN</string>
|
||||||
<string name="snInput_summary">Serial number pump base</string>
|
<string name="snInput_summary">Serial number pump base</string>
|
||||||
|
|
||||||
|
<string name="waitingforestimatedbolusend">Waiting for bolus end. Remaining %1$d sec.</string>
|
||||||
|
<string name="gettingbolusstatus">Getting bolus status</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue