From 28c0f1b8940ecdb877b8c0d28eecd37d3af7daec Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sat, 24 Apr 2021 19:11:01 +0100 Subject: [PATCH] - all files kotlinized - started some refactoring - added adrians refactoring of MedtronicCommunicationManager --- .../nightscout/androidaps/db/DbObjectBase.kt | 4 +- medtronic/build.gradle | 3 - .../pump/medtronic/MedtronicPumpPlugin.kt | 55 +- .../comm/MedtronicCommunicationManager.kt | 101 +- .../pump/medtronic/comm/MedtronicConverter.kt | 112 +- .../comm/history/MedtronicHistoryDecoder.kt | 16 +- .../MedtronicHistoryDecoderInterface.kt | 2 +- .../cgms/MedtronicCGMSHistoryDecoder.kt | 26 +- .../pump/MedtronicPumpHistoryDecoder.kt | 4 +- .../pump/medtronic/comm/ui/MedtronicUIComm.kt | 15 +- .../medtronic/data/MedtronicHistoryData.java | 1590 ----------------- .../medtronic/data/MedtronicHistoryData.kt | 1152 ++++++++++++ .../pump/medtronic/data/dto/BasalProfile.kt | 29 +- .../medtronic/defs/MedtronicCommandType.kt | 86 +- .../medtronic/defs/MedtronicDeviceType.kt | 39 +- .../pump/medtronic/di/MedtronicModule.kt | 3 + .../service/RileyLinkMedtronicService.kt | 7 +- 17 files changed, 1409 insertions(+), 1835 deletions(-) delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.kt diff --git a/core/src/main/java/info/nightscout/androidaps/db/DbObjectBase.kt b/core/src/main/java/info/nightscout/androidaps/db/DbObjectBase.kt index 76228abe9b..e8e4be360f 100644 --- a/core/src/main/java/info/nightscout/androidaps/db/DbObjectBase.kt +++ b/core/src/main/java/info/nightscout/androidaps/db/DbObjectBase.kt @@ -2,6 +2,6 @@ package info.nightscout.androidaps.db interface DbObjectBase { - val date: Long - val pumpId: Long + fun getDate(): Long + fun getPumpId(): Long } \ No newline at end of file diff --git a/medtronic/build.gradle b/medtronic/build.gradle index 0488efd078..a3cb9f789e 100644 --- a/medtronic/build.gradle +++ b/medtronic/build.gradle @@ -12,9 +12,6 @@ android { versionCode 1 versionName "1.0" } - dataBinding { - enabled = true - } } dependencies { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt index 64bb650744..a32a8937e2 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt @@ -364,13 +364,13 @@ class MedtronicPumpPlugin @Inject constructor( } MedtronicStatusRefreshType.BatteryStatus, MedtronicStatusRefreshType.RemainingInsulin -> { - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(key.getCommandType(medtronicUtil.medtronicPumpModel)!!) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(key.getCommandType(medtronicUtil.medtronicPumpModel)!!) refreshTypesNeededToReschedule.add(key) resetTime = true } MedtronicStatusRefreshType.Configuration -> { - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(key.getCommandType(medtronicUtil.medtronicPumpModel)!!) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(key.getCommandType(medtronicUtil.medtronicPumpModel)!!) resetTime = true } } @@ -415,7 +415,7 @@ class MedtronicPumpPlugin @Inject constructor( // model (once) if (medtronicUtil.medtronicPumpModel == null) { - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.PumpModel) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.PumpModel) } else { if (medtronicPumpStatus.medtronicDeviceType !== medtronicUtil.medtronicPumpModel) { aapsLogger.warn(LTag.PUMP, logPrefix + "Configured pump is not the same as one detected.") @@ -429,19 +429,19 @@ class MedtronicPumpPlugin @Inject constructor( readPumpHistory() // remaining insulin (>50 = 4h; 50-20 = 1h; 15m) - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetRemainingInsulin) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetRemainingInsulin) scheduleNextRefresh(MedtronicStatusRefreshType.RemainingInsulin, 10) // remaining power (1h) - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetBatteryStatus) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetBatteryStatus) scheduleNextRefresh(MedtronicStatusRefreshType.BatteryStatus, 20) // configuration (once and then if history shows config changes) - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(getSettings(medtronicUtil.medtronicPumpModel)) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(getSettings(medtronicUtil.medtronicPumpModel)) // read profile (once, later its controlled by isThisProfileSet method) basalProfiles - val errorCount = rileyLinkMedtronicService!!.medtronicUIComm!!.invalidResponsesCount + val errorCount = rileyLinkMedtronicService!!.medtronicUIComm.invalidResponsesCount if (errorCount >= 5) { aapsLogger.error("Number of error counts was 5 or more. Starting tunning.") setRefreshButtonEnabled(true) @@ -461,9 +461,9 @@ class MedtronicPumpPlugin @Inject constructor( private val basalProfiles: Unit private get() { - val medtronicUITask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetBasalProfileSTD) + val medtronicUITask = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetBasalProfileSTD) if (medtronicUITask.responseType === MedtronicUIResponseType.Error) { - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetBasalProfileSTD) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetBasalProfileSTD) } } @@ -492,7 +492,7 @@ class MedtronicPumpPlugin @Inject constructor( for (basalValue in profile.basalValues) { val basalValueValue = pumpDescription.pumpType.determineCorrectBasalSize(basalValue.value) val hour = basalValue.timeAsSeconds / (60 * 60) - if (!isSame(basalsByHour[hour]!!, basalValueValue)) { + if (!isSame(basalsByHour[hour], basalValueValue)) { invalid = true } stringBuilder.append(String.format(Locale.ENGLISH, "%.3f", basalValueValue)) @@ -551,10 +551,10 @@ class MedtronicPumpPlugin @Inject constructor( return } medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus) - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetRealTimeClock) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetRealTimeClock) var clock = medtronicUtil.pumpTime if (clock == null) { // retry - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetRealTimeClock) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetRealTimeClock) clock = medtronicUtil.pumpTime } if (clock == null) return @@ -562,7 +562,7 @@ class MedtronicPumpPlugin @Inject constructor( if (timeDiff > 20) { if (clock.localDeviceTime!!.year <= 2015 || timeDiff <= 24 * 60 * 60) { aapsLogger.info(LTag.PUMP, String.format(Locale.ENGLISH, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Time difference is %d s. Set time on pump.", timeDiff)) - rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.SetRealTimeClock) + rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.SetRealTimeClock) if (clock.timeDifference == 0) { val notification = Notification(Notification.INSIGHT_DATE_TIME_UPDATED, resourceHelper.gs(R.string.pump_time_updated), Notification.INFO, 60) rxBus.send(EventNewNotification(notification)) @@ -611,8 +611,8 @@ class MedtronicPumpPlugin @Inject constructor( bolusDeliveryType = BolusDeliveryType.Delivering // LOG.debug("MedtronicPumpPlugin::deliverBolus - Start delivery"); - val responseTask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.SetBolus, - Arrays.asList(detailedBolusInfo.insulin)) + val responseTask = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.SetBolus, + arrayListOf(detailedBolusInfo.insulin)) val response = responseTask.result as Boolean? setRefreshButtonEnabled(true) @@ -621,12 +621,7 @@ class MedtronicPumpPlugin @Inject constructor( if (bolusDeliveryType == BolusDeliveryType.CancelDelivery) { // LOG.debug("MedtronicPumpPlugin::deliverBolus - Delivery Canceled after Bolus started."); Thread(Runnable { - - // Looper.prepare(); - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Show dialog - before"); SystemClock.sleep(2000) - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Show dialog. Context: " - // + MainApp.instance().getApplicationContext()); runAlarm(context, resourceHelper.gs(R.string.medtronic_cmd_cancel_bolus_not_supported), resourceHelper.gs(R.string.medtronic_warning), R.raw.boluserror) }).start() } @@ -743,7 +738,7 @@ class MedtronicPumpPlugin @Inject constructor( aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - TBR running - so canceling it.") // CANCEL - val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.CancelTBR) + val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.CancelTBR) val response = responseTask2.result as Boolean? if (response!!) { aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - Current TBR cancelled.") @@ -756,8 +751,8 @@ class MedtronicPumpPlugin @Inject constructor( } // now start new TBR - val responseTask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.SetTemporaryBasal, - Arrays.asList(absoluteRate, durationInMinutes)) + val responseTask = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.SetTemporaryBasal, + arrayListOf(absoluteRate, durationInMinutes)) val response = responseTask.result as Boolean? aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - setTBR. Response: " + response) return if (response!!) { @@ -853,7 +848,7 @@ class MedtronicPumpPlugin @Inject constructor( } else { // LocalDateTime lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime); if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: " + lastPumpHistoryEntryTime + " - targetDate: " + targetDate) - medtronicHistoryData.setLastHistoryRecordTime(lastPumpHistoryEntryTime) + //medtronicHistoryData.setLastHistoryRecordTime(lastPumpHistoryEntryTime) var lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime) lastHistoryRecordTime = lastHistoryRecordTime.minusHours(12) // we get last 12 hours of history to // determine pump state @@ -873,8 +868,8 @@ class MedtronicPumpPlugin @Inject constructor( } //aapsLogger.debug(LTag.PUMP, "HST: Target Date: " + targetDate); - val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetHistoryData, - Arrays.asList(lastPumpHistoryEntry, targetDate) as List?) + val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetHistoryData, + arrayListOf(lastPumpHistoryEntry, targetDate) as ArrayList?) if (debugHistory) aapsLogger.debug(LTag.PUMP, "HST: After task") val historyResult = responseTask2.result as PumpHistoryResult? if (debugHistory) aapsLogger.debug(LTag.PUMP, "HST: History Result: " + historyResult.toString()) @@ -971,7 +966,7 @@ class MedtronicPumpPlugin @Inject constructor( } private fun readTBR(): TempBasalPair? { - val responseTask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.ReadTemporaryBasal) + val responseTask = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.ReadTemporaryBasal) return if (responseTask.hasData()) { val tbr = responseTask.result as TempBasalPair? @@ -1009,7 +1004,7 @@ class MedtronicPumpPlugin @Inject constructor( return PumpEnactResult(injector).success(false).enacted(false) .comment(R.string.medtronic_cmd_cant_read_tbr) } - val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.CancelTBR) + val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.CancelTBR) val response = responseTask2.result as Boolean? finishAction("TBR") return if (response!!) { @@ -1070,8 +1065,8 @@ class MedtronicPumpPlugin @Inject constructor( .enacted(false) // .comment(resourceHelper.gs(R.string.medtronic_cmd_set_profile_pattern_overflow, profileInvalid)) } - val responseTask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.SetBasalProfileSTD, - Arrays.asList(basalProfile)) + val responseTask = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.SetBasalProfileSTD, + arrayListOf(basalProfile)) val response = responseTask.result as Boolean? aapsLogger.info(LTag.PUMP, logPrefix + "Basal Profile was set: " + response) return if (response!!) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt index e913ff52f7..531e6f3422 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt @@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.pump.medtronic.comm import android.os.SystemClock import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkCommunicationManager import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RileyLinkCommunicationException @@ -64,7 +65,7 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth private var doWakeUpBeforeCommand = true @Inject - open fun onInit(): Unit { + fun onInit(): Unit { // we can't do this in the constructor, as sp only gets injected after the constructor has returned medtronicPumpStatus.previousConnection = sp.getLong( RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L) @@ -133,8 +134,7 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth } else { // radioResponse.rssi; - val dataResponse = medtronicConverter!!.convertResponse(medtronicPumpStatus.pumpType, MedtronicCommandType.PumpModel, - pumpResponse.rawContent) + val dataResponse = medtronicConverter.decodeModel(pumpResponse.rawContent) val pumpModel = dataResponse as MedtronicDeviceType? val valid = pumpModel !== MedtronicDeviceType.Unknown_Device if (medtronicUtil.medtronicPumpModel == null && valid) { @@ -350,11 +350,11 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth return when (type) { RLMessageType.PowerOn -> medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.RFPowerOn, byteArrayOf(2, 1, receiverDeviceAwakeForMinutes.toByte())) // maybe this is better FIXME RLMessageType.ReadSimpleData -> medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.PumpModel, null) + else -> ByteArray(0) } - return ByteArray(0) } - private fun makePumpMessage(messageType: MedtronicCommandType, body: ByteArray? = null as ByteArray?): PumpMessage { + private fun makePumpMessage(messageType: MedtronicCommandType, body: ByteArray? = null): PumpMessage { return makePumpMessage(messageType, body?.let { CarelinkShortMessageBody(it) } ?: CarelinkShortMessageBody()) } @@ -400,14 +400,21 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth return super.sendAndListen(msg, timeout_ms)!! } - private fun sendAndGetResponseWithCheck(commandType: MedtronicCommandType, bodyData: ByteArray? = null): Any? { + private inline fun sendAndGetResponseWithCheck( + commandType: MedtronicCommandType, + bodyData: ByteArray? = null, + decode: (pumpType: PumpType, commandType: MedtronicCommandType, rawContent: ByteArray?) -> T + ): T? { aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: $commandType") for (retries in 0 until MAX_COMMAND_TRIES) { try { val response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + DEFAULT_TIMEOUT * retries) val check = checkResponseContent(response, commandType.commandDescription, commandType.expectedLength) if (check == null) { - val dataResponse = medtronicConverter.convertResponse(medtronicPumpStatus.pumpType, commandType, response.rawContent) + + checkResponseRawContent(response.rawContent, commandType) { return@sendAndGetResponseWithCheck null } + + val dataResponse = decode(medtronicPumpStatus.pumpType, commandType, response.rawContent) if (dataResponse != null) { errorResponse = null aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name, dataResponse)) @@ -426,6 +433,16 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth return null } + private inline fun checkResponseRawContent(rawContent: ByteArray?, commandType: MedtronicCommandType, errorCase: () -> Unit) { + if (rawContent?.isEmpty() != false && commandType != MedtronicCommandType.PumpModel) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Content is empty or too short, no data to convert (type=%s,isNull=%b,length=%s)", + commandType.name, rawContent == null, rawContent?.size ?: "-")) + errorCase.invoke() + } else { + aapsLogger.debug(LTag.PUMPCOMM, "Raw response before convert: " + ByteUtil.shortHexString(rawContent)) + } + } + // private fun sendAndGetResponseWithCheck(commandType: MedtronicCommandType, bodyData: ByteArray, clazz: Class): T? { // aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: $commandType") // for (retries in 0 until MAX_COMMAND_TRIES) { @@ -479,13 +496,15 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth // PUMP SPECIFIC COMMANDS fun getRemainingInsulin(): Double? { - val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRemainingInsulin) - return if (responseObject == null) null else responseObject as Double? + return sendAndGetResponseWithCheck(MedtronicCommandType.GetRemainingInsulin) { _, _, rawContent -> + medtronicConverter.decodeRemainingInsulin(rawContent) + } } fun getPumpModel(): MedtronicDeviceType? { - val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.PumpModel) - return if (responseObject == null) null else responseObject as MedtronicDeviceType? + return sendAndGetResponseWithCheck(MedtronicCommandType.PumpModel) { _, _, rawContent -> + medtronicConverter.decodeModel(rawContent) + } } @@ -531,7 +550,12 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth } else { errorResponse = check } - val basalProfile = medtronicConverter.convertResponse(medtronicPumpPlugin.pumpType, commandType, data) as BasalProfile? + + var basalProfile: BasalProfile? = null + checkResponseRawContent(data, commandType) { + basalProfile = medtronicConverter.decodeBasalProfile(medtronicPumpPlugin.pumpDescription.pumpType, data) + } + if (basalProfile != null) { aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name, basalProfile)) medtronicUtil.setCurrentCommand(null) @@ -568,22 +592,24 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth fun getPumpTime(): ClockDTO? { val clockDTO = ClockDTO() clockDTO.localDeviceTime = LocalDateTime() - val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRealTimeClock) + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRealTimeClock) { _, _, rawContent -> + medtronicConverter.decodeTime(rawContent) + } if (responseObject != null) { - clockDTO.pumpTime = responseObject as LocalDateTime? + clockDTO.pumpTime = responseObject return clockDTO } return null } fun getTemporaryBasal(): TempBasalPair? { - val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.ReadTemporaryBasal) - return if (responseObject == null) null else responseObject as TempBasalPair? + return sendAndGetResponseWithCheck(MedtronicCommandType.ReadTemporaryBasal) { _, _, rawContent -> + TempBasalPair(aapsLogger, rawContent!!) } } fun getPumpSettings(): Map? { - val responseObject = sendAndGetResponseWithCheck(getSettings(medtronicUtil.medtronicPumpModel)) - return if (responseObject == null) null else responseObject as Map? + return sendAndGetResponseWithCheck(getSettings(medtronicUtil.medtronicPumpModel)) { _, _, rawContent -> + medtronicConverter.decodeSettingsLoop(rawContent) } } fun setBolus(units: Double): Boolean { @@ -600,20 +626,32 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth val gc = GregorianCalendar() gc.add(Calendar.SECOND, 5) aapsLogger.info(LTag.PUMPCOMM, "setPumpTime: " + DateTimeUtil.toString(gc)) - val i = 1 - val data = ByteArray(8) - data[0] = 7 - data[i] = gc[Calendar.HOUR_OF_DAY].toByte() - data[i + 1] = gc[Calendar.MINUTE].toByte() - data[i + 2] = gc[Calendar.SECOND].toByte() val yearByte = getByteArrayFromUnsignedShort(gc[Calendar.YEAR], true) - data[i + 3] = yearByte[0] - data[i + 4] = yearByte[1] - data[i + 5] = (gc[Calendar.MONTH] + 1).toByte() - data[i + 6] = gc[Calendar.DAY_OF_MONTH].toByte() + // val i = 1 + // val data = ByteArray(8) + // data[0] = 7 + // data[i] = gc[Calendar.HOUR_OF_DAY].toByte() + // data[i + 1] = gc[Calendar.MINUTE].toByte() + // data[i + 2] = gc[Calendar.SECOND].toByte() + // val yearByte = getByteArrayFromUnsignedShort(gc[Calendar.YEAR], true) + // data[i + 3] = yearByte[0] + // data[i + 4] = yearByte[1] + // data[i + 5] = (gc[Calendar.MONTH] + 1).toByte() + // data[i + 6] = gc[Calendar.DAY_OF_MONTH].toByte() + + val timeData = byteArrayOf( + 7, + gc[Calendar.HOUR_OF_DAY].toByte(), + gc[Calendar.MINUTE].toByte(), + gc[Calendar.SECOND].toByte(), + yearByte[0], + yearByte[1], + (gc[Calendar.MONTH] + 1).toByte(), + gc[Calendar.DAY_OF_MONTH].toByte() + ) //aapsLogger.info(LTag.PUMPCOMM,"setPumpTime: Body: " + ByteUtil.getHex(data)); - return setCommand(MedtronicCommandType.SetRealTimeClock, data) + return setCommand(MedtronicCommandType.SetRealTimeClock, timeData) } private fun setCommand(commandType: MedtronicCommandType, body: ByteArray): Boolean { @@ -642,8 +680,9 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth } fun getRemainingBattery(): BatteryStatusDTO? { - val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus) - return if (responseObject == null) null else responseObject as BatteryStatusDTO? + return sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus) { _, _, rawContent -> + medtronicConverter.decodeBatteryStatus(rawContent) + } } fun setBasalProfile(basalProfile: BasalProfile): Boolean { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.kt index a15fb131b7..49416f66c8 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.kt @@ -29,62 +29,62 @@ class MedtronicConverter @Inject constructor( private val medtronicUtil: MedtronicUtil ) { - fun convertResponse(pumpType: PumpType, commandType: MedtronicCommandType, rawContent: ByteArray?): Any? { - if ((rawContent == null || rawContent.size < 1) && commandType != MedtronicCommandType.PumpModel) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Content is empty or too short, no data to convert (type=%s,isNull=%b,length=%s)", - commandType.name, rawContent == null, rawContent?.size ?: "-")) - return null - } - aapsLogger.debug(LTag.PUMPCOMM, "Raw response before convert: " + ByteUtil.shortHexString(rawContent)) - return when (commandType) { - MedtronicCommandType.PumpModel -> { - decodeModel(rawContent) - } + // fun convertResponse(pumpType: PumpType, commandType: MedtronicCommandType, rawContent: ByteArray?): Any? { + // if ((rawContent == null || rawContent.size < 1) && commandType != MedtronicCommandType.PumpModel) { + // aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Content is empty or too short, no data to convert (type=%s,isNull=%b,length=%s)", + // commandType.name, rawContent == null, rawContent?.size ?: "-")) + // return null + // } + // aapsLogger.debug(LTag.PUMPCOMM, "Raw response before convert: " + ByteUtil.shortHexString(rawContent)) + // return when (commandType) { + // MedtronicCommandType.PumpModel -> { + // decodeModel(rawContent) + // } + // + // MedtronicCommandType.GetRealTimeClock -> { + // decodeTime(rawContent) + // } + // + // MedtronicCommandType.GetRemainingInsulin -> { + // decodeRemainingInsulin(rawContent) + // } + // + // MedtronicCommandType.GetBatteryStatus -> { + // decodeBatteryStatus(rawContent) // 1 + // } + // + // MedtronicCommandType.GetBasalProfileSTD, MedtronicCommandType.GetBasalProfileA, MedtronicCommandType.GetBasalProfileB -> { + // decodeBasalProfile(pumpType, rawContent) + // } + // + // MedtronicCommandType.ReadTemporaryBasal -> { + // TempBasalPair(aapsLogger, rawContent!!) // 5 + // } + // + // MedtronicCommandType.Settings_512 -> { + // decodeSettingsLoop(rawContent) + // } + // + // MedtronicCommandType.Settings -> { + // decodeSettingsLoop(rawContent) + // } + // + // MedtronicCommandType.SetBolus -> { + // rawContent // 1 + // } + // + // else -> { + // throw RuntimeException("Unsupported command Type: $commandType") + // } + // } + // } - MedtronicCommandType.GetRealTimeClock -> { - decodeTime(rawContent) - } - - MedtronicCommandType.GetRemainingInsulin -> { - decodeRemainingInsulin(rawContent) - } - - MedtronicCommandType.GetBatteryStatus -> { - decodeBatteryStatus(rawContent) // 1 - } - - MedtronicCommandType.GetBasalProfileSTD, MedtronicCommandType.GetBasalProfileA, MedtronicCommandType.GetBasalProfileB -> { - decodeBasalProfile(pumpType, rawContent) - } - - MedtronicCommandType.ReadTemporaryBasal -> { - TempBasalPair(aapsLogger, rawContent!!) // 5 - } - - MedtronicCommandType.Settings_512 -> { - decodeSettingsLoop(rawContent) - } - - MedtronicCommandType.Settings -> { - decodeSettingsLoop(rawContent) - } - - MedtronicCommandType.SetBolus -> { - rawContent // 1 - } - - else -> { - throw RuntimeException("Unsupported command Type: $commandType") - } - } - } - - private fun decodeBasalProfile(pumpType: PumpType, rawContent: ByteArray?): BasalProfile? { + fun decodeBasalProfile(pumpType: PumpType, rawContent: ByteArray?): BasalProfile? { val basalProfile = BasalProfile(aapsLogger, rawContent!!) return if (basalProfile.verify(pumpType)) basalProfile else null } - private fun decodeModel(rawContent: ByteArray?): MedtronicDeviceType { + fun decodeModel(rawContent: ByteArray?): MedtronicDeviceType { if (rawContent == null || rawContent.size < 4) { aapsLogger.warn(LTag.PUMPCOMM, "Error reading PumpModel, returning Unknown_Device") return MedtronicDeviceType.Unknown_Device @@ -100,7 +100,7 @@ class MedtronicConverter @Inject constructor( return pumpModel } - private fun decodeBatteryStatus(rawData: ByteArray?): BatteryStatusDTO { + fun decodeBatteryStatus(rawData: ByteArray?): BatteryStatusDTO { // 00 7C 00 00 val batteryStatus = BatteryStatusDTO() val status = rawData!![0].toInt() @@ -126,7 +126,7 @@ class MedtronicConverter @Inject constructor( return batteryStatus } - private fun decodeRemainingInsulin(rawData: ByteArray?): Double { + public fun decodeRemainingInsulin(rawData: ByteArray?): Double { var startIdx = 0 val pumpModel = medtronicUtil.medtronicPumpModel val strokes = pumpModel?.bolusStrokes ?: 10 @@ -134,7 +134,7 @@ class MedtronicConverter @Inject constructor( startIdx = 2 } val reqLength = startIdx + 1 - var value = 0.0 + val value : Double value = if (reqLength >= rawData!!.size) { rawData[startIdx] / (1.0 * strokes) } else { @@ -144,7 +144,7 @@ class MedtronicConverter @Inject constructor( return value } - private fun decodeTime(rawContent: ByteArray?): LocalDateTime? { + public fun decodeTime(rawContent: ByteArray?): LocalDateTime? { val hours = ByteUtil.asUINT8(rawContent!![0]) val minutes = ByteUtil.asUINT8(rawContent[1]) val seconds = ByteUtil.asUINT8(rawContent[2]) @@ -160,7 +160,7 @@ class MedtronicConverter @Inject constructor( } } - private fun decodeSettingsLoop(rd: ByteArray?): Map { + public fun decodeSettingsLoop(rd: ByteArray?): Map { val map: MutableMap = HashMap() addSettingToMap("PCFG_MAX_BOLUS", "" + decodeMaxBolus(rd), PumpConfigurationGroup.Bolus, map) addSettingToMap( diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt index 0a4db88ede..91d64f3efc 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt @@ -35,19 +35,19 @@ abstract class MedtronicHistoryDecoder : MedtronicHi // TODO_ extend this to also use bigger pages (for now we support only 1024 pages) @Throws(RuntimeException::class) - private fun checkPage(page: RawHistoryPage, partial: Boolean): List { - val byteList: List = ArrayList() + private fun checkPage(page: RawHistoryPage, partial: Boolean): MutableList { + //val byteList: MutableList = mutableListOf() if (medtronicUtil.medtronicPumpModel == null) { aapsLogger.error(LTag.PUMPCOMM, "Device Type is not defined.") - return byteList + return mutableListOf() } return if (page.data.size != 1024) { - ByteUtil.getListFromByteArray(page.data) + page.data.toMutableList() } else if (page.isChecksumOK) { - ByteUtil.getListFromByteArray(page.onlyData) + page.onlyData.toMutableList() } else { - byteList + mutableListOf() } } @@ -117,9 +117,9 @@ abstract class MedtronicHistoryDecoder : MedtronicHi return StringUtil.getFormatedValueUS(value, decimals) } - private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): List { + private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): MutableList { val dataClear = checkPage(rawHistoryPage, partial) - val records: List = createRecords(dataClear) + val records: MutableList = createRecords(dataClear) for (record in records) { decodeRecord(record) } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt index 1137371843..8b2ee5d2b0 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt @@ -6,5 +6,5 @@ package info.nightscout.androidaps.plugins.pump.medtronic.comm.history interface MedtronicHistoryDecoderInterface { fun decodeRecord(record: T): RecordDecodeStatus? - fun createRecords(dataClear: List): List + fun createRecords(dataClear: MutableList): MutableList } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt index 83a20262cc..7ce380ca4b 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt @@ -63,11 +63,12 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() override fun postProcess() {} - override fun createRecords(dataClearInput: List): List { - val dataClear = reverseList(dataClearInput, Byte::class.java) + override fun createRecords(dataClearInput: MutableList): MutableList { + dataClearInput.reverse() + val dataClear = dataClearInput //reverseList(dataClearInput, Byte::class.java) prepareStatistics() var counter = 0 - val outList: MutableList = ArrayList() + val outList: MutableList = mutableListOf() // create CGMS entries (without dates) do { @@ -109,7 +110,8 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() outList.add(pe) } } while (counter < dataClear.size) - val reversedOutList = reverseList(outList, CGMSHistoryEntry::class.java) + outList.reverse() + val reversedOutList = outList // reverseList(outList, CGMSHistoryEntry::class.java) var timeStamp: Long? = null var dateTime: LocalDateTime? = null var getIndex = 0 @@ -119,7 +121,7 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() timeStamp = entry.atechDateTime dateTime = DateTimeUtil.toLocalDateTime(timeStamp!!) getIndex = 0 - } else if (entry.entryType === CGMSHistoryEntryType.GlucoseSensorData) { + } else if (entry.entryType == CGMSHistoryEntryType.GlucoseSensorData) { getIndex++ if (dateTime != null) entry.setDateTime(dateTime, getIndex) } else { @@ -130,13 +132,13 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() return reversedOutList } - private fun reverseList(dataClearInput: List, clazz: Class): List { - val outList: MutableList = ArrayList() - for (i in dataClearInput.size - 1 downTo 1) { - outList.add(dataClearInput[i]) - } - return outList - } + // private fun reverseList(dataClearInput: List, clazz: Class): List { + // val outList: MutableList = ArrayList() + // for (i in dataClearInput.size - 1 downTo 1) { + // outList.add(dataClearInput[i]) + // } + // return outList + // } private fun parseMinutes(one: Int): Int { return one and "0111111".toInt(2) diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt index e9131694d2..452faa705d 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt @@ -37,12 +37,12 @@ class MedtronicPumpHistoryDecoder @Inject constructor( private var tbrPreviousRecord: PumpHistoryEntry? = null private var changeTimeRecord: PumpHistoryEntry? = null - override fun createRecords(dataClear: List): List { + override fun createRecords(dataClear: MutableList): MutableList { prepareStatistics() var counter = 0 var record = 0 var incompletePacket: Boolean - val outList: MutableList = ArrayList() + val outList: MutableList = mutableListOf() var skipped: String? = null if (dataClear.size == 0) { aapsLogger.error(LTag.PUMPBTCOMM, "Empty page.") diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.kt index 4cdb5766ec..3bff5105ee 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.kt @@ -6,16 +6,17 @@ import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.medtronic.comm.MedtronicCommunicationManager import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import javax.inject.Inject /** * Created by andy on 6/14/18. */ -class MedtronicUIComm( - private val injector: HasAndroidInjector, - private val aapsLogger: AAPSLogger, - private val medtronicUtil: MedtronicUtil, - private val medtronicUIPostprocessor: MedtronicUIPostprocessor, - private val medtronicCommunicationManager: MedtronicCommunicationManager +class MedtronicUIComm @Inject constructor( + private val injector: HasAndroidInjector, + private val aapsLogger: AAPSLogger, + private val medtronicUtil: MedtronicUtil, + private val medtronicUIPostprocessor: MedtronicUIPostprocessor, + private val medtronicCommunicationManager: MedtronicCommunicationManager ) { fun executeCommand(commandType: MedtronicCommandType): MedtronicUITask { @@ -23,7 +24,7 @@ class MedtronicUIComm( } @Synchronized - fun executeCommand(commandType: MedtronicCommandType, parameters: List?): MedtronicUITask { + fun executeCommand(commandType: MedtronicCommandType, parameters: ArrayList?): MedtronicUITask { aapsLogger.info(LTag.PUMP, "Execute Command: " + commandType.name) val task = MedtronicUITask(injector, commandType, parameters) diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java deleted file mode 100644 index 070bfb1a38..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java +++ /dev/null @@ -1,1590 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import org.apache.commons.lang3.StringUtils; -import org.joda.time.LocalDateTime; -import org.joda.time.Minutes; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.db.DbObjectBase; -import info.nightscout.androidaps.db.ExtendedBolus; -import info.nightscout.androidaps.db.Source; -import info.nightscout.androidaps.db.TDD; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.db.Treatment; -import info.nightscout.androidaps.interfaces.ActivePlugin; -import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; -import info.nightscout.androidaps.interfaces.PumpSync; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.MedtronicPumpHistoryDecoder; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BolusDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BolusWizardDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.DailyTotalsDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalProcessDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; -import info.nightscout.androidaps.plugins.treatments.TreatmentUpdateReturn; -import info.nightscout.androidaps.utils.Round; -import info.nightscout.androidaps.utils.sharedPreferences.SP; - - -/** - * Created by andy on 10/12/18. - */ - -// TODO: After release we need to refactor how data is retrieved from pump, each entry in history needs to be marked, and sorting -// needs to happen according those markings, not on time stamp (since AAPS can change time anytime it drifts away). This -// needs to include not returning any records if TZ goes into -x area. To fully support this AAPS would need to take note of -// all times that time changed (TZ, DST, etc.). Data needs to be returned in batches (time_changed batches, so that we can -// handle it. It would help to assign sort_ids to items (from oldest (1) to newest (x) - -// All things marked with "TODO: Fix db code" needs to be updated in new 2.5 database code - -@Singleton -public class MedtronicHistoryData { - - private final HasAndroidInjector injector; - private final AAPSLogger aapsLogger; - private final SP sp; - private final ActivePlugin activePlugin; - private final MedtronicUtil medtronicUtil; - private final MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder; - private final MedtronicPumpStatus medtronicPumpStatus; - private final DatabaseHelperInterface databaseHelper; - private final PumpSync pumpSync; - - private final List allHistory; - private List newHistory = null; - - private boolean isInit = false; - - private Gson gson; // cannot be initialized in constructor because of injection - private Gson gsonCore; // cannot be initialized in constructor because of injection - - private ClockDTO pumpTime; - - private long lastIdUsed = 0; - - /** - * Double bolus debug. We seem to have small problem with double Boluses (or sometimes also missing boluses - * from history. This flag turns on debugging for that (default is off=false)... Debugging is pretty detailed, - * so log files will get bigger. - * Note: June 2020. Since this seems to be fixed, I am disabling this per default. I will leave code inside - * in case we need it again. Code that turns this on is commented out RileyLinkMedtronicService#verifyConfiguration() - */ - public static final boolean doubleBolusDebug = false; - - @Inject - public MedtronicHistoryData( - HasAndroidInjector injector, - AAPSLogger aapsLogger, - SP sp, - ActivePlugin activePlugin, - MedtronicUtil medtronicUtil, - MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder, - MedtronicPumpStatus medtronicPumpStatus, - DatabaseHelperInterface databaseHelperInterface, - PumpSync pumpSync - ) { - this.allHistory = new ArrayList<>(); - - this.injector = injector; - this.aapsLogger = aapsLogger; - this.sp = sp; - this.activePlugin = activePlugin; - this.medtronicUtil = medtronicUtil; - this.medtronicPumpHistoryDecoder = medtronicPumpHistoryDecoder; - this.medtronicPumpStatus = medtronicPumpStatus; - this.databaseHelper = databaseHelperInterface; - this.pumpSync = pumpSync; - } - - private Gson gson() { - if (gson == null) gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); - return gson; - } - - private Gson gsonCore() { - if (gsonCore == null) gsonCore = new GsonBuilder().create(); - return gsonCore; - } - - /** - * Add New History entries - * - * @param result PumpHistoryResult instance - */ - public void addNewHistory(PumpHistoryResult result) { - - List validEntries = result.getValidEntries(); - - List newEntries = new ArrayList<>(); - - for (PumpHistoryEntry validEntry : validEntries) { - - if (!this.allHistory.contains(validEntry)) { - newEntries.add(validEntry); - } - } - - this.newHistory = newEntries; - - showLogs("List of history (before filtering): [" + this.newHistory.size() + "]", gson().toJson(this.newHistory)); - } - - - private void showLogs(String header, String data) { - if (header != null) { - aapsLogger.debug(LTag.PUMP, header); - } - - if (StringUtils.isNotBlank(data)) { - for (final String token : StringUtil.splitString(data, 3500)) { - aapsLogger.debug(LTag.PUMP, token); - } - } else { - aapsLogger.debug(LTag.PUMP, "No data."); - } - } - - - public List getAllHistory() { - return this.allHistory; - } - - - public void filterNewEntries() { - - List newHistory2 = new ArrayList<>(); - List TBRs = new ArrayList<>(); - List bolusEstimates = new ArrayList<>(); - long atechDate = DateTimeUtil.toATechDate(new GregorianCalendar()); - - //aapsLogger.debug(LTag.PUMP, "Filter new entries: Before {}", newHistory); - - if (!isCollectionEmpty(newHistory)) { - - for (PumpHistoryEntry pumpHistoryEntry : newHistory) { - - if (!this.allHistory.contains(pumpHistoryEntry)) { - - PumpHistoryEntryType type = pumpHistoryEntry.getEntryType(); - - if (type == PumpHistoryEntryType.TempBasalRate || type == PumpHistoryEntryType.TempBasalDuration) { - TBRs.add(pumpHistoryEntry); - } else if (type == PumpHistoryEntryType.BolusWizard || type == PumpHistoryEntryType.BolusWizard512) { - bolusEstimates.add(pumpHistoryEntry); - newHistory2.add(pumpHistoryEntry); - } else { - - if (type == PumpHistoryEntryType.EndResultTotals) { - if (!DateTimeUtil.isSameDay(atechDate, pumpHistoryEntry.getAtechDateTime())) { - newHistory2.add(pumpHistoryEntry); - } - } else { - newHistory2.add(pumpHistoryEntry); - } - } - } - } - - TBRs = preProcessTBRs(TBRs); - - if (bolusEstimates.size() > 0) { - extendBolusRecords(bolusEstimates, newHistory2); - } - - newHistory2.addAll(TBRs); - - this.newHistory = newHistory2; - - sort(this.newHistory); - } - - aapsLogger.debug(LTag.PUMP, "New History entries found: " + this.newHistory.size()); - - showLogs("List of history (after filtering): [" + this.newHistory.size() + "]", gson().toJson(this.newHistory)); - - } - - private void extendBolusRecords(List bolusEstimates, List newHistory2) { - - List boluses = getFilteredItems(newHistory2, PumpHistoryEntryType.Bolus); - - for (PumpHistoryEntry bolusEstimate : bolusEstimates) { - for (PumpHistoryEntry bolus : boluses) { - if (bolusEstimate.getAtechDateTime().equals(bolus.getAtechDateTime())) { - bolus.addDecodedData("Estimate", bolusEstimate.getDecodedData().get("Object")); - } - } - } - } - - - public void finalizeNewHistoryRecords() { - - if ((newHistory == null) || (newHistory.size() == 0)) - return; - - PumpHistoryEntry pheLast = newHistory.get(0); - - // find last entry - for (PumpHistoryEntry pumpHistoryEntry : newHistory) { - if (pumpHistoryEntry.getAtechDateTime() != null && pumpHistoryEntry.isAfter(pheLast.getAtechDateTime())) { - pheLast = pumpHistoryEntry; - } - } - - // add new entries - Collections.reverse(newHistory); - - for (PumpHistoryEntry pumpHistoryEntry : newHistory) { - - if (!this.allHistory.contains(pumpHistoryEntry)) { - lastIdUsed++; - pumpHistoryEntry.setId(lastIdUsed); - this.allHistory.add(pumpHistoryEntry); - } - - } - - - if (pheLast == null) // if we don't have any valid record we don't do the filtering and setting - return; - - this.setLastHistoryRecordTime(pheLast.getAtechDateTime()); - sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, pheLast.getAtechDateTime()); - - LocalDateTime dt = null; - - try { - dt = DateTimeUtil.toLocalDateTime(pheLast.getAtechDateTime()); - } catch (Exception ex) { - aapsLogger.error("Problem decoding date from last record: " + pheLast); - } - - if (dt != null) { - - dt = dt.minusDays(1); // we keep 24 hours - - long dtRemove = DateTimeUtil.toATechDate(dt); - - List removeList = new ArrayList<>(); - - for (PumpHistoryEntry pumpHistoryEntry : allHistory) { - - if (!pumpHistoryEntry.isAfter(dtRemove)) { - removeList.add(pumpHistoryEntry); - } - } - - this.allHistory.removeAll(removeList); - - this.sort(this.allHistory); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "All History records [afterFilterCount=%d, removedItemsCount=%d, newItemsCount=%d]", - allHistory.size(), removeList.size(), newHistory.size())); - } else { - aapsLogger.error("Since we couldn't determine date, we don't clean full history. This is just workaround."); - } - - this.newHistory.clear(); - } - - - public boolean hasRelevantConfigurationChanged() { - return getStateFromFilteredList( // - PumpHistoryEntryType.ChangeBasalPattern, // - PumpHistoryEntryType.ClearSettings, // - PumpHistoryEntryType.SaveSettings, // - PumpHistoryEntryType.ChangeMaxBolus, // - PumpHistoryEntryType.ChangeMaxBasal, // - PumpHistoryEntryType.ChangeTempBasalType); - } - - - private boolean isCollectionEmpty(List col) { - return (col == null || col.isEmpty()); - } - - private boolean isCollectionNotEmpty(List col) { - return (col != null && !col.isEmpty()); - } - - - public boolean isPumpSuspended() { - - List items = getDataForPumpSuspends(); - - showLogs("isPumpSuspended: ", gson().toJson(items)); - - if (isCollectionNotEmpty(items)) { - - PumpHistoryEntryType pumpHistoryEntryType = items.get(0).getEntryType(); - - boolean isSuspended = !(pumpHistoryEntryType == PumpHistoryEntryType.TempBasalCombined || // - pumpHistoryEntryType == PumpHistoryEntryType.BasalProfileStart || // - pumpHistoryEntryType == PumpHistoryEntryType.Bolus || // - pumpHistoryEntryType == PumpHistoryEntryType.ResumePump || // - pumpHistoryEntryType == PumpHistoryEntryType.BatteryChange || // - pumpHistoryEntryType == PumpHistoryEntryType.Prime); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "isPumpSuspended. Last entry type=%s, isSuspended=%b", pumpHistoryEntryType, isSuspended)); - - return isSuspended; - } else - return false; - - } - - - private List getDataForPumpSuspends() { - - List newAndAll = new ArrayList<>(); - - if (isCollectionNotEmpty(this.allHistory)) { - newAndAll.addAll(this.allHistory); - } - - if (isCollectionNotEmpty(this.newHistory)) { - - for (PumpHistoryEntry pumpHistoryEntry : newHistory) { - if (!newAndAll.contains(pumpHistoryEntry)) { - newAndAll.add(pumpHistoryEntry); - } - } - } - - if (newAndAll.isEmpty()) - return newAndAll; - - this.sort(newAndAll); - - List newAndAll2 = getFilteredItems(newAndAll, // - PumpHistoryEntryType.Bolus, // - PumpHistoryEntryType.TempBasalCombined, // - PumpHistoryEntryType.Prime, // - PumpHistoryEntryType.SuspendPump, // - PumpHistoryEntryType.ResumePump, // - PumpHistoryEntryType.Rewind, // - PumpHistoryEntryType.NoDeliveryAlarm, // - PumpHistoryEntryType.BatteryChange, // - PumpHistoryEntryType.BasalProfileStart); - - newAndAll2 = filterPumpSuspend(newAndAll2, 10); - - return newAndAll2; - } - - - private List filterPumpSuspend(List newAndAll, int filterCount) { - - if (newAndAll.size() <= filterCount) { - return newAndAll; - } - - List newAndAllOut = new ArrayList<>(); - - for (int i = 0; i < filterCount; i++) { - newAndAllOut.add(newAndAll.get(i)); - } - - return newAndAllOut; - } - - - /** - * Process History Data: Boluses(Treatments), TDD, TBRs, Suspend-Resume (or other pump stops: battery, prime) - */ - public void processNewHistoryData() { - - // TODO: Fix db code - // Prime (for reseting autosense) - List primeRecords = getFilteredItems(PumpHistoryEntryType.Prime); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: Prime [count=%d, items=%s]", primeRecords.size(), gson().toJson(primeRecords))); - - if (isCollectionNotEmpty(primeRecords)) { - try { - processPrime(primeRecords); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Prime entries: " + ex.getMessage(), ex); - throw ex; - } - } - - // Rewind (for marking insulin change) - List rewindRecords = getFilteredItems(PumpHistoryEntryType.Rewind); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: Rewind [count=%d, items=%s]", rewindRecords.size(), gson().toJson(rewindRecords))); - - if (isCollectionNotEmpty(rewindRecords)) { - try { - processRewind(rewindRecords); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Rewind entries: " + ex.getMessage(), ex); - throw ex; - } - } - - // TDD - List tdds = getFilteredItems(PumpHistoryEntryType.EndResultTotals, getTDDType()); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: TDD [count=%d, items=%s]", tdds.size(), gson().toJson(tdds))); - - if (isCollectionNotEmpty(tdds)) { - try { - processTDDs(tdds); - } catch (Exception ex) { - aapsLogger.error("ProcessHistoryData: Error processing TDD entries: " + ex.getMessage(), ex); - throw ex; - } - } - - pumpTime = medtronicUtil.getPumpTime(); - - // Bolus - List treatments = getFilteredItems(PumpHistoryEntryType.Bolus); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: Bolus [count=%d, items=%s]", treatments.size(), gson().toJson(treatments))); - - if (treatments.size() > 0) { - try { - processBolusEntries(treatments); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Bolus entries: " + ex.getMessage(), ex); - throw ex; - } - } - - // TBR - List tbrs = getFilteredItems(PumpHistoryEntryType.TempBasalCombined); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: TBRs Processed [count=%d, items=%s]", tbrs.size(), gson().toJson(tbrs))); - - if (tbrs.size() > 0) { - try { - processTBREntries(tbrs); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing TBR entries: " + ex.getMessage(), ex); - throw ex; - } - } - - // 'Delivery Suspend' - List suspends; - - try { - suspends = getSuspends(); - } catch (Exception ex) { - aapsLogger.error("ProcessHistoryData: Error getting Suspend entries: " + ex.getMessage(), ex); - throw ex; - } - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: 'Delivery Suspend' Processed [count=%d, items=%s]", suspends.size(), - gson().toJson(suspends))); - - if (isCollectionNotEmpty(suspends)) { - try { - processSuspends(suspends); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Suspends entries: " + ex.getMessage(), ex); - throw ex; - } - } - } - - - private void processPrime(List primeRecords) { - - long maxAllowedTimeInPast = DateTimeUtil.getATDWithAddedMinutes(new GregorianCalendar(), -30); - - long lastPrimeRecord = 0L; - - for (PumpHistoryEntry primeRecord : primeRecords) { - Object fixedAmount = primeRecord.getDecodedDataEntry("FixedAmount"); - - if (fixedAmount != null && ((float) fixedAmount) == 0.0f) { - // non-fixed primes are used to prime the tubing - // fixed primes are used to prime the cannula - // so skip the prime entry if it was not a fixed prime - continue; - } - - if (primeRecord.getAtechDateTime() > maxAllowedTimeInPast) { - if (lastPrimeRecord < primeRecord.getAtechDateTime()) { - lastPrimeRecord = primeRecord.getAtechDateTime(); - } - } - } - - if (lastPrimeRecord != 0L) { - long lastPrimeFromAAPS = sp.getLong(MedtronicConst.Statistics.LastPrime, 0L); - - if (lastPrimeRecord != lastPrimeFromAAPS) { - uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastPrimeRecord), DetailedBolusInfo.EventType.CANNULA_CHANGE); - - sp.putLong(MedtronicConst.Statistics.LastPrime, lastPrimeRecord); - } - } - } - - private void processRewind(List rewindRecords) { - long maxAllowedTimeInPast = DateTimeUtil.getATDWithAddedMinutes(new GregorianCalendar(), -30); - long lastRewindRecord = 0L; - - for (PumpHistoryEntry rewindRecord : rewindRecords) { - if (rewindRecord.getAtechDateTime() > maxAllowedTimeInPast) { - if (lastRewindRecord < rewindRecord.getAtechDateTime()) { - lastRewindRecord = rewindRecord.getAtechDateTime(); - } - } - } - - if (lastRewindRecord != 0L) { - long lastRewindFromAAPS = sp.getLong(MedtronicConst.Statistics.LastRewind, 0L); - - if (lastRewindRecord != lastRewindFromAAPS) { - uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastRewindRecord), DetailedBolusInfo.EventType.INSULIN_CHANGE); - - sp.putLong(MedtronicConst.Statistics.LastRewind, lastRewindRecord); - } - } - } - - - private void uploadCareportalEvent(long date, DetailedBolusInfo.EventType event) { - pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, - medtronicPumpStatus.getPumpType(), medtronicPumpStatus.getSerialNumber()); - } - - private void processTDDs(List tddsIn) { - - List tdds = filterTDDs(tddsIn); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, getLogPrefix() + "TDDs found: %d.\n%s", tdds.size(), gson().toJson(tdds))); - - List tddsDb = databaseHelper.getTDDsForLastXDays(3); - - for (PumpHistoryEntry tdd : tdds) { - - TDD tddDbEntry = findTDD(tdd.getAtechDateTime(), tddsDb); - - DailyTotalsDTO totalsDTO = (DailyTotalsDTO) tdd.getDecodedData().get("Object"); - - //aapsLogger.debug(LTag.PUMP, "DailyTotals: {}", totalsDTO); - - if (tddDbEntry == null) { - TDD tddNew = new TDD(); - totalsDTO.setTDD(tddNew); - - aapsLogger.debug(LTag.PUMP, "TDD Add: " + tddNew); - - databaseHelper.createOrUpdateTDD(tddNew); - - } else { - - if (!totalsDTO.doesEqual(tddDbEntry)) { - totalsDTO.setTDD(tddDbEntry); - - aapsLogger.debug(LTag.PUMP, "TDD Edit: " + tddDbEntry); - - databaseHelper.createOrUpdateTDD(tddDbEntry); - } - } - } - } - - - private enum ProcessHistoryRecord { - Bolus("Bolus"), - TBR("TBR"), - Suspend("Suspend"); - - private final String description; - - ProcessHistoryRecord(String desc) { - this.description = desc; - } - - public String getDescription() { - return this.description; - } - - } - - - private void processBolusEntries(List entryList) { - - long oldestTimestamp = getOldestTimestamp(entryList); - - List entriesFromHistory = getDatabaseEntriesByLastTimestamp(oldestTimestamp, ProcessHistoryRecord.Bolus); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: List (before filter): %s, FromDb=%s", gson().toJson(entryList), - gsonCore().toJson(entriesFromHistory))); - - filterOutAlreadyAddedEntries(entryList, entriesFromHistory); - - if (entryList.isEmpty()) { - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: EntryList was filtered out."); - return; - } - - filterOutNonInsulinEntries(entriesFromHistory); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: List (after filter): %s, FromDb=%s", gson().toJson(entryList), - gsonCore().toJson(entriesFromHistory))); - - if (isCollectionEmpty(entriesFromHistory)) { - for (PumpHistoryEntry treatment : entryList) { - aapsLogger.debug(LTag.PUMP, "Add Bolus (no db entry): " + treatment); - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: Add Bolus: FromDb=null, Treatment=" + treatment); - - addBolus(treatment, null); - } - } else { - for (PumpHistoryEntry treatment : entryList) { - DbObjectBase treatmentDb = findDbEntry(treatment, entriesFromHistory); - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Add Bolus %s - (entryFromDb=%s) ", treatment, treatmentDb)); - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: Add Bolus: FromDb=%s, Treatment=%s", treatmentDb, treatment)); - - addBolus(treatment, (Treatment) treatmentDb); - } - } - } - - - private void filterOutNonInsulinEntries(List entriesFromHistory) { - // when we try to pair PumpHistory with AAPS treatments, we need to ignore all non-insulin entries - List removeList = new ArrayList<>(); - - for (DbObjectBase dbObjectBase : entriesFromHistory) { - - Treatment treatment = (Treatment) dbObjectBase; - - if (Round.isSame(treatment.insulin, 0d)) { - removeList.add(dbObjectBase); - } - } - - entriesFromHistory.removeAll(removeList); - } - - - private void processTBREntries(List entryList) { - - Collections.reverse(entryList); - - TempBasalPair tbr = (TempBasalPair) entryList.get(0).getDecodedDataEntry("Object"); - - boolean readOldItem = false; - - if (tbr.isCancelTBR()) { - PumpHistoryEntry oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.TempBasalCombined); - - if (oneMoreEntryFromHistory != null) { - entryList.add(0, oneMoreEntryFromHistory); - readOldItem = true; - } else { - entryList.remove(0); - } - } - - long oldestTimestamp = getOldestTimestamp(entryList); - - List entriesFromHistory = getDatabaseEntriesByLastTimestamp(oldestTimestamp, ProcessHistoryRecord.TBR); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, ProcessHistoryRecord.TBR.getDescription() + " List (before filter): %s, FromDb=%s", gson().toJson(entryList), - gson().toJson(entriesFromHistory))); - - - TempBasalProcessDTO processDTO = null; - List processList = new ArrayList<>(); - - for (PumpHistoryEntry treatment : entryList) { - - TempBasalPair tbr2 = (TempBasalPair) treatment.getDecodedDataEntry("Object"); - - if (tbr2.isCancelTBR()) { - - if (processDTO != null) { - processDTO.itemTwo = treatment; - - if (readOldItem) { - processDTO.processOperation = TempBasalProcessDTO.Operation.Edit; - readOldItem = false; - } - } else { - aapsLogger.error("processDTO was null - shouldn't happen. ItemTwo=" + treatment); - } - } else { - if (processDTO != null) { - processList.add(processDTO); - } - - processDTO = new TempBasalProcessDTO(); - processDTO.itemOne = treatment; - processDTO.processOperation = TempBasalProcessDTO.Operation.Add; - } - } - - if (processDTO != null) { - processList.add(processDTO); - } - - - if (isCollectionNotEmpty(processList)) { - - for (TempBasalProcessDTO tempBasalProcessDTO : processList) { - - if (tempBasalProcessDTO.processOperation == TempBasalProcessDTO.Operation.Edit) { - // edit - TemporaryBasal tempBasal = findTempBasalWithPumpId(tempBasalProcessDTO.itemOne.getPumpId(), entriesFromHistory); - - if (tempBasal != null) { - - tempBasal.durationInMinutes = tempBasalProcessDTO.getDuration(); - - databaseHelper.createOrUpdate(tempBasal); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Edit " + ProcessHistoryRecord.TBR.getDescription() + " - (entryFromDb=%s) ", tempBasal)); - } else { - aapsLogger.error(LTag.PUMP, "TempBasal not found. Item: " + tempBasalProcessDTO.itemOne); - } - - } else { - // add - - PumpHistoryEntry treatment = tempBasalProcessDTO.itemOne; - - TempBasalPair tbr2 = (TempBasalPair) treatment.getDecodedData().get("Object"); - tbr2.setDurationMinutes(tempBasalProcessDTO.getDuration()); - - TemporaryBasal tempBasal = findTempBasalWithPumpId(tempBasalProcessDTO.itemOne.getPumpId(), entriesFromHistory); - - if (tempBasal == null) { - DbObjectBase treatmentDb = findDbEntry(treatment, entriesFromHistory); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Add " + ProcessHistoryRecord.TBR.getDescription() + " %s - (entryFromDb=%s) ", treatment, treatmentDb)); - - addTBR(treatment, (TemporaryBasal) treatmentDb); - } else { - // this shouldn't happen - if (tempBasal.durationInMinutes != tempBasalProcessDTO.getDuration()) { - aapsLogger.debug(LTag.PUMP, "Found entry with wrong duration (shouldn't happen)... updating"); - tempBasal.durationInMinutes = tempBasalProcessDTO.getDuration(); - } - - } - } // if - } // for - - } // collection - } - - - private TemporaryBasal findTempBasalWithPumpId(long pumpId, List entriesFromHistory) { - - for (DbObjectBase dbObjectBase : entriesFromHistory) { - TemporaryBasal tbr = (TemporaryBasal) dbObjectBase; - - if (tbr.pumpId == pumpId) { - return tbr; - } - } - - TemporaryBasal tempBasal = databaseHelper.findTempBasalByPumpId(pumpId); - return tempBasal; - } - - - /** - * findDbEntry - finds Db entries in database, while theoretically this should have same dateTime they - * don't. Entry on pump is few seconds before treatment in AAPS, and on manual boluses on pump there - * is no treatment at all. For now we look fro tratment that was from 0s - 1m59s within pump entry. - * - * @param treatment Pump Entry - * @param entriesFromHistory entries from history - * @return DbObject from AAPS (if found) - */ - private DbObjectBase findDbEntry(PumpHistoryEntry treatment, List entriesFromHistory) { - - long proposedTime = DateTimeUtil.toMillisFromATD(treatment.getAtechDateTime()); - - //proposedTime += (this.pumpTime.timeDifference * 1000); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Treatment=%s, FromDb=%s", treatment, gson().toJson(entriesFromHistory))); - - if (entriesFromHistory.size() == 0) { - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Treatment=%s, FromDb=null", treatment)); - return null; - } else if (entriesFromHistory.size() == 1) { - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Treatment=%s, FromDb=%s. Type=SingleEntry", treatment, entriesFromHistory.get(0))); - - // TODO: Fix db code - // if difference is bigger than 2 minutes we discard entry - long maxMillisAllowed = DateTimeUtil.getMillisFromATDWithAddedMinutes(treatment.getAtechDateTime(), 2); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry maxMillisAllowed=%d, AtechDateTime=%d (add 2 minutes). ", maxMillisAllowed, treatment.getAtechDateTime())); - - if (entriesFromHistory.get(0).getDate() > maxMillisAllowed) { - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: findDbEntry entry filtered out, returning null. "); - return null; - } - - return entriesFromHistory.get(0); - } - - for (int min = 0; min < 2; min += 1) { - - for (int sec = 0; sec <= 50; sec += 10) { - - if (min == 1 && sec == 50) { - sec = 59; - } - - int diff = (sec * 1000); - - List outList = new ArrayList<>(); - - for (DbObjectBase treatment1 : entriesFromHistory) { - - if ((treatment1.getDate() > proposedTime - diff) && (treatment1.getDate() < proposedTime + diff)) { - outList.add(treatment1); - } - } - - if (outList.size() == 1) { - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Treatment={}, FromDb={}. Type=EntrySelected, AtTimeMin={}, AtTimeSec={}", treatment, entriesFromHistory.get(0), min, sec)); - - return outList.get(0); - } - - if (min == 0 && sec == 10 && outList.size() > 1) { - aapsLogger.error(String.format(Locale.ENGLISH, "Too many entries (with too small diff): (timeDiff=[min=%d,sec=%d],count=%d,list=%s)", - min, sec, outList.size(), gson().toJson(outList))); - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Error - Too many entries (with too small diff): (timeDiff=[min=%d,sec=%d],count=%d,list=%s)", - min, sec, outList.size(), gson().toJson(outList))); - } - } - } - - return null; - } - - - private List getDatabaseEntriesByLastTimestamp(long startTimestamp, ProcessHistoryRecord processHistoryRecord) { - if (processHistoryRecord == ProcessHistoryRecord.Bolus) { - return activePlugin.getActiveTreatments().getTreatmentsFromHistoryAfterTimestamp(startTimestamp); - } else { - return databaseHelper.getTemporaryBasalsDataFromTime(startTimestamp, true); - } - } - - - private void filterOutAlreadyAddedEntries(List entryList, List treatmentsFromHistory) { - - if (isCollectionEmpty(treatmentsFromHistory)) - return; - - List removeTreatmentsFromHistory = new ArrayList<>(); - List removeTreatmentsFromPH = new ArrayList<>(); - - for (DbObjectBase treatment : treatmentsFromHistory) { - - if (treatment.getPumpId() != 0) { - - PumpHistoryEntry selectedBolus = null; - - for (PumpHistoryEntry bolus : entryList) { - if (bolus.getPumpId() == treatment.getPumpId()) { - selectedBolus = bolus; - break; - } - } - - if (selectedBolus != null) { - entryList.remove(selectedBolus); - - removeTreatmentsFromPH.add(selectedBolus); - removeTreatmentsFromHistory.add(treatment); - } - } - } - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: filterOutAlreadyAddedEntries: PumpHistory=%s, Treatments=%s", - gson().toJson(removeTreatmentsFromPH), - gsonCore().toJson(removeTreatmentsFromHistory))); - - treatmentsFromHistory.removeAll(removeTreatmentsFromHistory); - } - - - private void addBolus(PumpHistoryEntry bolus, Treatment treatment) { - - BolusDTO bolusDTO = (BolusDTO) bolus.getDecodedData().get("Object"); - - if (treatment == null) { - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): Bolus=" + bolusDTO); - - switch (bolusDTO.getBolusType()) { - case Normal: { - DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); - - detailedBolusInfo.setBolusTimestamp(tryToGetByLocalTime(bolus.getAtechDateTime())); - detailedBolusInfo.setPumpType(PumpType.MEDTRONIC_512_712); // TODO grab real model - detailedBolusInfo.setPumpSerial(medtronicPumpStatus.getSerialNumber()); - detailedBolusInfo.setBolusPumpId(bolus.getPumpId()); - detailedBolusInfo.insulin = bolusDTO.getDeliveredAmount(); - - addCarbsFromEstimate(detailedBolusInfo, bolus); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): DetailedBolusInfo=" + detailedBolusInfo); - - boolean newRecord = activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false); - - bolus.setLinkedObject(detailedBolusInfo); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "addBolus - [date=%d,pumpId=%d, insulin=%.2f, newRecord=%b]", detailedBolusInfo.timestamp, - detailedBolusInfo.getBolusPumpId(), detailedBolusInfo.insulin, newRecord)); - } - break; - - case Audio: - case Extended: { - ExtendedBolus extendedBolus = new ExtendedBolus(injector); - extendedBolus.date = tryToGetByLocalTime(bolus.getAtechDateTime()); - extendedBolus.source = Source.PUMP; - extendedBolus.insulin = bolusDTO.getDeliveredAmount(); - extendedBolus.pumpId = bolus.getPumpId(); - extendedBolus.isValid = true; - extendedBolus.durationInMinutes = bolusDTO.getDuration(); - - bolus.setLinkedObject(extendedBolus); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): ExtendedBolus=" + extendedBolus); - - activePlugin.getActiveTreatments().addToHistoryExtendedBolus(extendedBolus); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "addBolus - Extended [date=%d,pumpId=%d, insulin=%.3f, duration=%d]", extendedBolus.date, - extendedBolus.pumpId, extendedBolus.insulin, extendedBolus.durationInMinutes)); - - } - break; - } - - } else { - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: addBolus(OldTreatment=%s): Bolus=%s", treatment, bolusDTO)); - - treatment.source = Source.PUMP; - treatment.pumpId = bolus.getPumpId(); - treatment.insulin = bolusDTO.getDeliveredAmount(); - - TreatmentUpdateReturn updateReturn = activePlugin.getActiveTreatments().createOrUpdateMedtronic(treatment, false); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: addBolus(tretament!=null): NewTreatment=%s, UpdateReturn=%s", treatment, updateReturn)); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "editBolus - [date=%d,pumpId=%d, insulin=%.3f, newRecord=%s]", treatment.date, - treatment.pumpId, treatment.insulin, updateReturn.toString())); - - bolus.setLinkedObject(treatment); - - } - } - - - private void addCarbsFromEstimate(DetailedBolusInfo detailedBolusInfo, PumpHistoryEntry bolus) { - - if (bolus.containsDecodedData("Estimate")) { - - BolusWizardDTO bolusWizard = (BolusWizardDTO) bolus.getDecodedData().get("Estimate"); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: addCarbsFromEstimate: Bolus=%s, BolusWizardDTO=%s", bolus, bolusWizard)); - - detailedBolusInfo.carbs = bolusWizard.getCarbs(); - } - } - - - private void addTBR(PumpHistoryEntry treatment, TemporaryBasal temporaryBasalDbInput) { - - TempBasalPair tbr = (TempBasalPair) treatment.getDecodedData().get("Object"); - - TemporaryBasal temporaryBasalDb = temporaryBasalDbInput; - String operation = "editTBR"; - - if (temporaryBasalDb == null) { - temporaryBasalDb = new TemporaryBasal(injector); - temporaryBasalDb.date = tryToGetByLocalTime(treatment.getAtechDateTime()); - - operation = "addTBR"; - } - - temporaryBasalDb.source = Source.PUMP; - temporaryBasalDb.pumpId = treatment.getPumpId(); - temporaryBasalDb.durationInMinutes = tbr.getDurationMinutes(); - temporaryBasalDb.absoluteRate = tbr.getInsulinRate(); - temporaryBasalDb.isAbsolute = !tbr.isPercent(); - - treatment.setLinkedObject(temporaryBasalDb); - - databaseHelper.createOrUpdate(temporaryBasalDb); - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, operation + " - [date=%d,pumpId=%d, rate=%s %s, duration=%d]", // - temporaryBasalDb.date, // - temporaryBasalDb.pumpId, // - temporaryBasalDb.isAbsolute ? String.format(Locale.ENGLISH, "%.2f", temporaryBasalDb.absoluteRate) : - String.format(Locale.ENGLISH, "%d", temporaryBasalDb.percentRate), // - temporaryBasalDb.isAbsolute ? "U/h" : "%", // - temporaryBasalDb.durationInMinutes)); - } - - - private void processSuspends(List tempBasalProcessList) { - - for (TempBasalProcessDTO tempBasalProcess : tempBasalProcessList) { - - TemporaryBasal tempBasal = databaseHelper.findTempBasalByPumpId(tempBasalProcess.itemOne.getPumpId()); - - if (tempBasal == null) { - // add - tempBasal = new TemporaryBasal(injector); - tempBasal.date = tryToGetByLocalTime(tempBasalProcess.itemOne.getAtechDateTime()); - - tempBasal.source = Source.PUMP; - tempBasal.pumpId = tempBasalProcess.itemOne.getPumpId(); - tempBasal.durationInMinutes = tempBasalProcess.getDuration(); - tempBasal.absoluteRate = 0.0d; - tempBasal.isAbsolute = true; - - tempBasalProcess.itemOne.setLinkedObject(tempBasal); - tempBasalProcess.itemTwo.setLinkedObject(tempBasal); - - databaseHelper.createOrUpdate(tempBasal); - - } - } - - } - - - private List getSuspends() { - - List outList = new ArrayList<>(); - - // suspend/resume - outList.addAll(getSuspendResumeRecords()); - // no_delivery/prime & rewind/prime - outList.addAll(getNoDeliveryRewindPrimeRecords()); - - return outList; - } - - private List getSuspendResumeRecords() { - List filteredItems = getFilteredItems(this.newHistory, // - PumpHistoryEntryType.SuspendPump, // - PumpHistoryEntryType.ResumePump); - - List outList = new ArrayList<>(); - - if (filteredItems.size() > 0) { - - List filtered2Items = new ArrayList<>(); - - if ((filteredItems.size() % 2 == 0) && (filteredItems.get(0).getEntryType() == PumpHistoryEntryType.ResumePump)) { - // full resume suspends (S R S R) - filtered2Items.addAll(filteredItems); - } else if ((filteredItems.size() % 2 == 0) && (filteredItems.get(0).getEntryType() == PumpHistoryEntryType.SuspendPump)) { - // not full suspends, need to retrive one more record and discard first one (R S R S) -> ([S] R S R [xS]) - filteredItems.remove(0); - - PumpHistoryEntry oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.SuspendPump); - if (oneMoreEntryFromHistory != null) { - filteredItems.add(oneMoreEntryFromHistory); - } else { - filteredItems.remove(filteredItems.size() - 1); // remove last (unpaired R) - } - - filtered2Items.addAll(filteredItems); - } else { - if (filteredItems.get(0).getEntryType() == PumpHistoryEntryType.ResumePump) { - // get one more from history (R S R) -> ([S] R S R) - - PumpHistoryEntry oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.SuspendPump); - if (oneMoreEntryFromHistory != null) { - filteredItems.add(oneMoreEntryFromHistory); - } else { - filteredItems.remove(filteredItems.size() - 1); // remove last (unpaired R) - } - - filtered2Items.addAll(filteredItems); - } else { - // remove last and have paired items - filteredItems.remove(0); - filtered2Items.addAll(filteredItems); - } - } - - if (filtered2Items.size() > 0) { - sort(filtered2Items); - Collections.reverse(filtered2Items); - - for (int i = 0; i < filtered2Items.size(); i += 2) { - TempBasalProcessDTO dto = new TempBasalProcessDTO(); - - dto.itemOne = filtered2Items.get(i); - dto.itemTwo = filtered2Items.get(i + 1); - - dto.processOperation = TempBasalProcessDTO.Operation.Add; - - outList.add(dto); - } - } - } - - return outList; - } - - - private List getNoDeliveryRewindPrimeRecords() { - List primeItems = getFilteredItems(this.newHistory, // - PumpHistoryEntryType.Prime); - - List outList = new ArrayList<>(); - - if (primeItems.size() == 0) - return outList; - - List filteredItems = getFilteredItems(this.newHistory, // - PumpHistoryEntryType.Prime, - PumpHistoryEntryType.Rewind, - PumpHistoryEntryType.NoDeliveryAlarm, - PumpHistoryEntryType.Bolus, - PumpHistoryEntryType.TempBasalCombined - ); - - List tempData = new ArrayList<>(); - boolean startedItems = false; - boolean finishedItems = false; - - for (PumpHistoryEntry filteredItem : filteredItems) { - if (filteredItem.getEntryType() == PumpHistoryEntryType.Prime) { - startedItems = true; - } - - if (startedItems) { - if (filteredItem.getEntryType() == PumpHistoryEntryType.Bolus || - filteredItem.getEntryType() == PumpHistoryEntryType.TempBasalCombined) { - finishedItems = true; - break; - } - - tempData.add(filteredItem); - } - } - - - if (!finishedItems) { - - List filteredItemsOld = getFilteredItems(this.allHistory, // - PumpHistoryEntryType.Rewind, - PumpHistoryEntryType.NoDeliveryAlarm, - PumpHistoryEntryType.Bolus, - PumpHistoryEntryType.TempBasalCombined - ); - - for (PumpHistoryEntry filteredItem : filteredItemsOld) { - - if (filteredItem.getEntryType() == PumpHistoryEntryType.Bolus || - filteredItem.getEntryType() == PumpHistoryEntryType.TempBasalCombined) { - finishedItems = true; - break; - } - - tempData.add(filteredItem); - } - } - - - if (!finishedItems) { - showLogs("NoDeliveryRewindPrimeRecords: Not finished Items: ", gson().toJson(tempData)); - return outList; - } - - showLogs("NoDeliveryRewindPrimeRecords: Records to evaluate: ", gson().toJson(tempData)); - - List items = getFilteredItems(tempData, // - PumpHistoryEntryType.Prime - ); - - - TempBasalProcessDTO processDTO = new TempBasalProcessDTO(); - - processDTO.itemTwo = items.get(0); - - items = getFilteredItems(tempData, // - PumpHistoryEntryType.NoDeliveryAlarm - ); - - if (items.size() > 0) { - - processDTO.itemOne = items.get(items.size() - 1); - processDTO.processOperation = TempBasalProcessDTO.Operation.Add; - - outList.add(processDTO); - return outList; - } - - - items = getFilteredItems(tempData, // - PumpHistoryEntryType.Rewind - ); - - if (items.size() > 0) { - - processDTO.itemOne = items.get(0); - processDTO.processOperation = TempBasalProcessDTO.Operation.Add; - - outList.add(processDTO); - return outList; - } - - return outList; - } - - - private PumpHistoryEntry getOneMoreEntryFromHistory(PumpHistoryEntryType entryType) { - List filteredItems = getFilteredItems(this.allHistory, entryType); - - return filteredItems.size() == 0 ? null : filteredItems.get(0); - } - - - private List filterTDDs(List tdds) { - List tddsOut = new ArrayList<>(); - - for (PumpHistoryEntry tdd : tdds) { - if (tdd.getEntryType() != PumpHistoryEntryType.EndResultTotals) { - tddsOut.add(tdd); - } - } - - return tddsOut.size() == 0 ? tdds : tddsOut; - } - - - private TDD findTDD(long atechDateTime, List tddsDb) { - - for (TDD tdd : tddsDb) { - - if (DateTimeUtil.isSameDayATDAndMillis(atechDateTime, tdd.date)) { - return tdd; - } - } - - return null; - } - - private long tryToGetByLocalTime(long atechDateTime) { - return DateTimeUtil.toMillisFromATD(atechDateTime); - } - - - private int getOldestDateDifference(List treatments) { - - long dt = Long.MAX_VALUE; - PumpHistoryEntry currentTreatment = null; - - if (isCollectionEmpty(treatments)) { - return 8; // default return of 6 (5 for diif on history reading + 2 for max allowed difference) minutes - } - - for (PumpHistoryEntry treatment : treatments) { - - if (treatment.getAtechDateTime() < dt) { - dt = treatment.getAtechDateTime(); - currentTreatment = treatment; - } - } - - LocalDateTime oldestEntryTime; - - try { - - oldestEntryTime = DateTimeUtil.toLocalDateTime(dt); - oldestEntryTime = oldestEntryTime.minusMinutes(3); - -// if (this.pumpTime.timeDifference < 0) { -// oldestEntryTime = oldestEntryTime.plusSeconds(this.pumpTime.timeDifference); -// } - } catch (Exception ex) { - aapsLogger.error("Problem decoding date from last record: " + currentTreatment); - return 8; // default return of 6 minutes - } - - LocalDateTime now = new LocalDateTime(); - - Minutes minutes = Minutes.minutesBetween(oldestEntryTime, now); - - // returns oldest time in history, with calculated time difference between pump and phone, minus 5 minutes - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Oldest entry: %d, pumpTimeDifference=%d, newDt=%s, currentTime=%s, differenceMin=%d", dt, - this.pumpTime.getTimeDifference(), oldestEntryTime, now, minutes.getMinutes())); - - return minutes.getMinutes(); - } - - - private long getOldestTimestamp(List treatments) { - - long dt = Long.MAX_VALUE; - PumpHistoryEntry currentTreatment = null; - - for (PumpHistoryEntry treatment : treatments) { - - if (treatment.getAtechDateTime() < dt) { - dt = treatment.getAtechDateTime(); - currentTreatment = treatment; - } - } - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: getOldestTimestamp. Oldest entry found: time=%d, object=%s", dt, currentTreatment)); - - try { - - GregorianCalendar oldestEntryTime = DateTimeUtil.toGregorianCalendar(dt); - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: getOldestTimestamp. oldestEntryTime: %s", DateTimeUtil.toString(oldestEntryTime))); - oldestEntryTime.add(Calendar.MINUTE, -2); - - if (doubleBolusDebug) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: getOldestTimestamp. oldestEntryTime (-2m): %s, timeInMillis=%d", DateTimeUtil.toString(oldestEntryTime), oldestEntryTime.getTimeInMillis())); - - return oldestEntryTime.getTimeInMillis(); - - } catch (Exception ex) { - aapsLogger.error("Problem decoding date from last record: " + currentTreatment); - return 8; // default return of 6 minutes - } - - } - - - private PumpHistoryEntryType getTDDType() { - - if (medtronicUtil.getMedtronicPumpModel() == null) { - return PumpHistoryEntryType.EndResultTotals; - } - - switch (medtronicUtil.getMedtronicPumpModel()) { - - case Medtronic_515: - case Medtronic_715: - return PumpHistoryEntryType.DailyTotals515; - - case Medtronic_522: - case Medtronic_722: - return PumpHistoryEntryType.DailyTotals522; - - case Medtronic_523_Revel: - case Medtronic_723_Revel: - case Medtronic_554_Veo: - case Medtronic_754_Veo: - return PumpHistoryEntryType.DailyTotals523; - - default: { - return PumpHistoryEntryType.EndResultTotals; - } - } - } - - - public boolean hasBasalProfileChanged() { - - List filteredItems = getFilteredItems(PumpHistoryEntryType.ChangeBasalProfile_NewProfile); - - aapsLogger.debug(LTag.PUMP, "hasBasalProfileChanged. Items: " + gson().toJson(filteredItems)); - - return (filteredItems.size() > 0); - } - - - public void processLastBasalProfileChange(PumpType pumpType, MedtronicPumpStatus mdtPumpStatus) { - - List filteredItems = getFilteredItems(PumpHistoryEntryType.ChangeBasalProfile_NewProfile); - - aapsLogger.debug(LTag.PUMP, "processLastBasalProfileChange. Items: " + filteredItems); - - PumpHistoryEntry newProfile = null; - Long lastDate = null; - - if (filteredItems.size() == 1) { - newProfile = filteredItems.get(0); - } else if (filteredItems.size() > 1) { - - for (PumpHistoryEntry filteredItem : filteredItems) { - - if (lastDate == null || lastDate < filteredItem.getAtechDateTime()) { - newProfile = filteredItem; - lastDate = newProfile.getAtechDateTime(); - } - } - } - - if (newProfile != null) { - aapsLogger.debug(LTag.PUMP, "processLastBasalProfileChange. item found, setting new basalProfileLocally: " + newProfile); - BasalProfile basalProfile = (BasalProfile) newProfile.getDecodedData().get("Object"); - - mdtPumpStatus.setBasalsByHour( basalProfile.getProfilesByHour(pumpType)); - } - } - - - public boolean hasPumpTimeChanged() { - return getStateFromFilteredList(PumpHistoryEntryType.NewTimeSet, // - PumpHistoryEntryType.ChangeTime); - } - - - public void setLastHistoryRecordTime(Long lastHistoryRecordTime) { - - // this.previousLastHistoryRecordTime = this.lastHistoryRecordTime; - } - - - public void setIsInInit(boolean init) { - this.isInit = init; - } - - - // HELPER METHODS - - private void sort(List list) { - if (list != null && !list.isEmpty()) { - Collections.sort(list, new PumpHistoryEntry.Comparator()); - } - } - - - private List preProcessTBRs(List TBRs_Input) { - List TBRs = new ArrayList<>(); - - Map map = new HashMap<>(); - - for (PumpHistoryEntry pumpHistoryEntry : TBRs_Input) { - if (map.containsKey(pumpHistoryEntry.getDT())) { - medtronicPumpHistoryDecoder.decodeTempBasal(map.get(pumpHistoryEntry.getDT()), pumpHistoryEntry); - pumpHistoryEntry.setEntryType(medtronicUtil.getMedtronicPumpModel(), PumpHistoryEntryType.TempBasalCombined); - TBRs.add(pumpHistoryEntry); - map.remove(pumpHistoryEntry.getDT()); - } else { - map.put(pumpHistoryEntry.getDT(), pumpHistoryEntry); - } - } - - return TBRs; - } - - - private List getFilteredItems(PumpHistoryEntryType... entryTypes) { - return getFilteredItems(this.newHistory, entryTypes); - } - - - private boolean getStateFromFilteredList(PumpHistoryEntryType... entryTypes) { - if (isInit) { - return false; - } else { - List filteredItems = getFilteredItems(entryTypes); - - aapsLogger.debug(LTag.PUMP, "Items: " + filteredItems); - - return filteredItems.size() > 0; - } - } - - - private List getFilteredItems(List inList, PumpHistoryEntryType... entryTypes) { - - // aapsLogger.debug(LTag.PUMP, "InList: " + inList.size()); - List outList = new ArrayList<>(); - - if (inList != null && inList.size() > 0) { - for (PumpHistoryEntry pumpHistoryEntry : inList) { - - if (!isEmpty(entryTypes)) { - for (PumpHistoryEntryType pumpHistoryEntryType : entryTypes) { - - if (pumpHistoryEntry.getEntryType() == pumpHistoryEntryType) { - outList.add(pumpHistoryEntry); - break; - } - } - } else { - outList.add(pumpHistoryEntry); - } - } - } - - // aapsLogger.debug(LTag.PUMP, "OutList: " + outList.size()); - - return outList; - } - - - private boolean isEmpty(PumpHistoryEntryType... entryTypes) { - return (entryTypes == null || (entryTypes.length == 1 && entryTypes[0] == null)); - } - - - private String getLogPrefix() { - return "MedtronicHistoryData::"; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.kt new file mode 100644 index 0000000000..dd81eafd00 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.kt @@ -0,0 +1,1152 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.db.* +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.DatabaseHelperInterface +import info.nightscout.androidaps.interfaces.PumpSync +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.MedtronicPumpHistoryDecoder +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.* +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpBolusType +import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import info.nightscout.androidaps.utils.Round +import info.nightscout.androidaps.utils.sharedPreferences.SP +import org.apache.commons.lang3.StringUtils +import org.joda.time.LocalDateTime +import org.joda.time.Minutes +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Created by andy on 10/12/18. + */ +// TODO: After release we need to refactor how data is retrieved from pump, each entry in history needs to be marked, and sorting +// needs to happen according those markings, not on time stamp (since AAPS can change time anytime it drifts away). This +// needs to include not returning any records if TZ goes into -x area. To fully support this AAPS would need to take note of +// all times that time changed (TZ, DST, etc.). Data needs to be returned in batches (time_changed batches, so that we can +// handle it. It would help to assign sort_ids to items (from oldest (1) to newest (x) +// All things marked with "TODO: Fix db code" needs to be updated in new 2.5 database code +@Suppress("DEPRECATION") +@Singleton +class MedtronicHistoryData @Inject constructor( + val injector: HasAndroidInjector, + val aapsLogger: AAPSLogger, + val sp: SP, + val activePlugin: ActivePlugin, + val medtronicUtil: MedtronicUtil, + val medtronicPumpHistoryDecoder: MedtronicPumpHistoryDecoder, + val medtronicPumpStatus: MedtronicPumpStatus, + val databaseHelper: DatabaseHelperInterface, + val pumpSync: PumpSync +) { + + val allHistory: MutableList = mutableListOf() + private var newHistory: MutableList = mutableListOf() + private var isInit = false + + private var pumpTime: ClockDTO? = null + private var lastIdUsed: Long = 0 + private var gson: Gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() + private var gsonCore: Gson = GsonBuilder().create() + + + /** + * Add New History entries + * + * @param result PumpHistoryResult instance + */ + fun addNewHistory(result: PumpHistoryResult) { + val validEntries: List = result.validEntries + val newEntries: MutableList = mutableListOf() + for (validEntry in validEntries) { + if (!allHistory.contains(validEntry)) { + newEntries.add(validEntry) + } + } + newHistory = newEntries + showLogs("List of history (before filtering): [" + newHistory.size + "]", gson.toJson(newHistory)) + } + + private fun showLogs(header: String?, data: String) { + if (header != null) { + aapsLogger.debug(LTag.PUMP, header) + } + if (StringUtils.isNotBlank(data)) { + for (token in StringUtil.splitString(data, 3500)) { + aapsLogger.debug(LTag.PUMP, token) + } + } else { + aapsLogger.debug(LTag.PUMP, "No data.") + } + } + + // fun getAllHistory(): List { + // return allHistory + // } + + fun filterNewEntries() { + val newHistory2: MutableList = mutableListOf() + var tbrs: MutableList = mutableListOf() + val bolusEstimates: MutableList = mutableListOf() + val atechDate = DateTimeUtil.toATechDate(GregorianCalendar()) + + //aapsLogger.debug(LTag.PUMP, "Filter new entries: Before {}", newHistory); + if (!isCollectionEmpty(newHistory)) { + for (pumpHistoryEntry in newHistory) { + if (!allHistory.contains(pumpHistoryEntry)) { + val type = pumpHistoryEntry.entryType + if (type === PumpHistoryEntryType.TempBasalRate || type === PumpHistoryEntryType.TempBasalDuration) { + tbrs.add(pumpHistoryEntry) + } else if (type === PumpHistoryEntryType.BolusWizard || type === PumpHistoryEntryType.BolusWizard512) { + bolusEstimates.add(pumpHistoryEntry) + newHistory2.add(pumpHistoryEntry) + } else { + if (type === PumpHistoryEntryType.EndResultTotals) { + if (!DateTimeUtil.isSameDay(atechDate, pumpHistoryEntry.atechDateTime!!)) { + newHistory2.add(pumpHistoryEntry) + } + } else { + newHistory2.add(pumpHistoryEntry) + } + } + } + } + tbrs = preProcessTBRs(tbrs) + if (bolusEstimates.size > 0) { + extendBolusRecords(bolusEstimates, newHistory2) + } + newHistory2.addAll(tbrs) + newHistory = newHistory2 + sort(newHistory) + } + aapsLogger.debug(LTag.PUMP, "New History entries found: " + newHistory.size) + showLogs("List of history (after filtering): [" + newHistory.size + "]", gson.toJson(newHistory)) + } + + private fun extendBolusRecords(bolusEstimates: MutableList, newHistory2: MutableList) { + val boluses: MutableList = getFilteredItems(newHistory2, PumpHistoryEntryType.Bolus) + for (bolusEstimate in bolusEstimates) { + for (bolus in boluses) { + if (bolusEstimate.atechDateTime == bolus.atechDateTime) { + bolus.addDecodedData("Estimate", bolusEstimate.decodedData!!["Object"]) + } + } + } + } + + fun finalizeNewHistoryRecords() { + if (newHistory.isEmpty()) return + var pheLast = newHistory[0] + + // find last entry + for (pumpHistoryEntry in newHistory) { + if (pumpHistoryEntry.atechDateTime != null && pumpHistoryEntry.isAfter(pheLast.atechDateTime!!)) { + pheLast = pumpHistoryEntry + } + } + + // add new entries + newHistory.reverse() + for (pumpHistoryEntry in newHistory) { + if (!allHistory.contains(pumpHistoryEntry)) { + lastIdUsed++ + pumpHistoryEntry.id = lastIdUsed + allHistory.add(pumpHistoryEntry) + } + } + // if (pheLast == null) // if we don't have any valid record we don't do the filtering and setting + // return + //setLastHistoryRecordTime(pheLast.atechDateTime) + sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, pheLast.atechDateTime!!) + var dt: LocalDateTime? = null + try { + dt = DateTimeUtil.toLocalDateTime(pheLast.atechDateTime!!) + } catch (ex: Exception) { + aapsLogger.error("Problem decoding date from last record: $pheLast") + } + if (dt != null) { + dt = dt.minusDays(1) // we keep 24 hours + val dtRemove = DateTimeUtil.toATechDate(dt) + val removeList: MutableList = ArrayList() + for (pumpHistoryEntry in allHistory) { + if (!pumpHistoryEntry.isAfter(dtRemove)) { + removeList.add(pumpHistoryEntry) + } + } + allHistory.removeAll(removeList) + this.sort(allHistory) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "All History records [afterFilterCount=%d, removedItemsCount=%d, newItemsCount=%d]", + allHistory.size, removeList.size, newHistory.size)) + } else { + aapsLogger.error("Since we couldn't determine date, we don't clean full history. This is just workaround.") + } + newHistory.clear() + } + + fun hasRelevantConfigurationChanged(): Boolean { + return getStateFromFilteredList( // + setOf(PumpHistoryEntryType.ChangeBasalPattern, // + PumpHistoryEntryType.ClearSettings, // + PumpHistoryEntryType.SaveSettings, // + PumpHistoryEntryType.ChangeMaxBolus, // + PumpHistoryEntryType.ChangeMaxBasal, // + PumpHistoryEntryType.ChangeTempBasalType)) + } + + private fun isCollectionEmpty(col: List<*>?): Boolean { + return col == null || col.isEmpty() + } + + private fun isCollectionNotEmpty(col: List<*>?): Boolean { + return col != null && !col.isEmpty() + }//////// + + // + val isPumpSuspended: Boolean + get() { + val items = getDataForPumpSuspends() + showLogs("isPumpSuspended: ", gson.toJson(items)) + return if (isCollectionNotEmpty(items)) { + val pumpHistoryEntryType = items[0].entryType + val isSuspended = !(pumpHistoryEntryType === PumpHistoryEntryType.TempBasalCombined || // + pumpHistoryEntryType === PumpHistoryEntryType.BasalProfileStart || // + pumpHistoryEntryType === PumpHistoryEntryType.Bolus || // + pumpHistoryEntryType === PumpHistoryEntryType.ResumePump || // + pumpHistoryEntryType === PumpHistoryEntryType.BatteryChange || // + pumpHistoryEntryType === PumpHistoryEntryType.Prime) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "isPumpSuspended. Last entry type=%s, isSuspended=%b", pumpHistoryEntryType, isSuspended)) + isSuspended + } else false + } + + private fun getDataForPumpSuspends(): MutableList { + val newAndAll: MutableList = mutableListOf() + if (isCollectionNotEmpty(allHistory)) { + newAndAll.addAll(allHistory) + } + if (isCollectionNotEmpty(newHistory)) { + for (pumpHistoryEntry in newHistory!!) { + if (!newAndAll.contains(pumpHistoryEntry)) { + newAndAll.add(pumpHistoryEntry) + } + } + } + if (newAndAll.isEmpty()) return newAndAll + this.sort(newAndAll) + var newAndAll2: MutableList = getFilteredItems(newAndAll, // + setOf(PumpHistoryEntryType.Bolus, // + PumpHistoryEntryType.TempBasalCombined, // + PumpHistoryEntryType.Prime, // + PumpHistoryEntryType.SuspendPump, // + PumpHistoryEntryType.ResumePump, // + PumpHistoryEntryType.Rewind, // + PumpHistoryEntryType.NoDeliveryAlarm, // + PumpHistoryEntryType.BatteryChange, // + PumpHistoryEntryType.BasalProfileStart)) + newAndAll2 = filterPumpSuspend(newAndAll2, 10) + return newAndAll2 + } + + private fun filterPumpSuspend(newAndAll: MutableList, filterCount: Int): MutableList { + if (newAndAll.size <= filterCount) { + return newAndAll + } + val newAndAllOut: MutableList = ArrayList() + for (i in 0 until filterCount) { + newAndAllOut.add(newAndAll[i]) + } + return newAndAllOut + } + + /** + * Process History Data: Boluses(Treatments), TDD, TBRs, Suspend-Resume (or other pump stops: battery, prime) + */ + fun processNewHistoryData() { + + // TODO: Fix db code + // Prime (for reseting autosense) + val primeRecords: MutableList = getFilteredItems(PumpHistoryEntryType.Prime) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: Prime [count=%d, items=%s]", primeRecords.size, gson.toJson(primeRecords))) + if (isCollectionNotEmpty(primeRecords)) { + try { + processPrime(primeRecords) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Prime entries: " + ex.message, ex) + throw ex + } + } + + // Rewind (for marking insulin change) + val rewindRecords: MutableList = getFilteredItems(PumpHistoryEntryType.Rewind) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: Rewind [count=%d, items=%s]", rewindRecords.size, gson.toJson(rewindRecords))) + if (isCollectionNotEmpty(rewindRecords)) { + try { + processRewind(rewindRecords) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Rewind entries: " + ex.message, ex) + throw ex + } + } + + // TDD + val tdds: MutableList = getFilteredItems(setOf(PumpHistoryEntryType.EndResultTotals, tDDType)) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: TDD [count=%d, items=%s]", tdds.size, gson.toJson(tdds))) + if (isCollectionNotEmpty(tdds)) { + try { + processTDDs(tdds) + } catch (ex: Exception) { + aapsLogger.error("ProcessHistoryData: Error processing TDD entries: " + ex.message, ex) + throw ex + } + } + pumpTime = medtronicUtil.pumpTime + + // Bolus + val treatments = getFilteredItems(PumpHistoryEntryType.Bolus) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: Bolus [count=%d, items=%s]", treatments.size, gson.toJson(treatments))) + if (treatments.size > 0) { + try { + processBolusEntries(treatments) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Bolus entries: " + ex.message, ex) + throw ex + } + } + + // TBR + val tbrs: MutableList = getFilteredItems(PumpHistoryEntryType.TempBasalCombined) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: TBRs Processed [count=%d, items=%s]", tbrs.size, gson.toJson(tbrs))) + if (tbrs.size > 0) { + try { + processTBREntries(tbrs) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing TBR entries: " + ex.message, ex) + throw ex + } + } + + // 'Delivery Suspend' + val suspends: MutableList + suspends = try { + getSuspendRecords() + } catch (ex: Exception) { + aapsLogger.error("ProcessHistoryData: Error getting Suspend entries: " + ex.message, ex) + throw ex + } + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: 'Delivery Suspend' Processed [count=%d, items=%s]", suspends.size, + gson.toJson(suspends))) + if (isCollectionNotEmpty(suspends)) { + try { + processSuspends(suspends) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Suspends entries: " + ex.message, ex) + throw ex + } + } + } + + private fun processPrime(primeRecords: List) { + val maxAllowedTimeInPast = DateTimeUtil.getATDWithAddedMinutes(GregorianCalendar(), -30) + var lastPrimeRecord = 0L + for (primeRecord in primeRecords) { + val fixedAmount = primeRecord!!.getDecodedDataEntry("FixedAmount") + if (fixedAmount != null && fixedAmount as Float == 0.0f) { + // non-fixed primes are used to prime the tubing + // fixed primes are used to prime the cannula + // so skip the prime entry if it was not a fixed prime + continue + } + if (primeRecord.atechDateTime!! > maxAllowedTimeInPast) { + if (lastPrimeRecord < primeRecord.atechDateTime!!) { + lastPrimeRecord = primeRecord.atechDateTime!! + } + } + } + if (lastPrimeRecord != 0L) { + val lastPrimeFromAAPS = sp.getLong(MedtronicConst.Statistics.LastPrime, 0L) + if (lastPrimeRecord != lastPrimeFromAAPS) { + uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastPrimeRecord), DetailedBolusInfo.EventType.CANNULA_CHANGE) + sp.putLong(MedtronicConst.Statistics.LastPrime, lastPrimeRecord) + } + } + } + + private fun processRewind(rewindRecords: List) { + val maxAllowedTimeInPast = DateTimeUtil.getATDWithAddedMinutes(GregorianCalendar(), -30) + var lastRewindRecord = 0L + for (rewindRecord in rewindRecords) { + if (rewindRecord!!.atechDateTime!! > maxAllowedTimeInPast) { + if (lastRewindRecord < rewindRecord.atechDateTime!!) { + lastRewindRecord = rewindRecord.atechDateTime!! + } + } + } + if (lastRewindRecord != 0L) { + val lastRewindFromAAPS = sp.getLong(MedtronicConst.Statistics.LastRewind, 0L) + if (lastRewindRecord != lastRewindFromAAPS) { + uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastRewindRecord), DetailedBolusInfo.EventType.INSULIN_CHANGE) + sp.putLong(MedtronicConst.Statistics.LastRewind, lastRewindRecord) + } + } + } + + private fun uploadCareportalEvent(date: Long, event: DetailedBolusInfo.EventType) { + pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, + medtronicPumpStatus.pumpType, medtronicPumpStatus.serialNumber!!) + } + + private fun processTDDs(tddsIn: MutableList) { + val tdds = filterTDDs(tddsIn) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, """ + ${logPrefix}TDDs found: %d. + %s + """.trimIndent(), tdds.size, gson.toJson(tdds))) + val tddsDb = databaseHelper.getTDDsForLastXDays(3) + for (tdd in tdds) { + val tddDbEntry = findTDD(tdd.atechDateTime!!, tddsDb) + val totalsDTO = tdd.decodedData!!["Object"] as DailyTotalsDTO? + + //aapsLogger.debug(LTag.PUMP, "DailyTotals: {}", totalsDTO); + if (tddDbEntry == null) { + val tddNew = TDD() + totalsDTO!!.setTDD(tddNew) + aapsLogger.debug(LTag.PUMP, "TDD Add: $tddNew") + databaseHelper.createOrUpdateTDD(tddNew) + } else { + if (!totalsDTO!!.doesEqual(tddDbEntry)) { + totalsDTO.setTDD(tddDbEntry) + aapsLogger.debug(LTag.PUMP, "TDD Edit: $tddDbEntry") + databaseHelper.createOrUpdateTDD(tddDbEntry) + } + } + } + } + + private enum class ProcessHistoryRecord(val description: String) { + Bolus("Bolus"), + TBR("TBR"), + Suspend("Suspend"); + } + + private fun processBolusEntries(entryList: MutableList) { + val oldestTimestamp = getOldestTimestamp(entryList) + val entriesFromHistory = getDatabaseEntriesByLastTimestamp(oldestTimestamp, ProcessHistoryRecord.Bolus) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: List (before filter): %s, FromDb=%s", gson.toJson(entryList), + gsonCore.toJson(entriesFromHistory))) + filterOutAlreadyAddedEntries(entryList, entriesFromHistory) + if (entryList.isEmpty()) { + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: EntryList was filtered out.") + return + } + filterOutNonInsulinEntries(entriesFromHistory) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: List (after filter): %s, FromDb=%s", gson.toJson(entryList), + gsonCore.toJson(entriesFromHistory))) + if (isCollectionEmpty(entriesFromHistory)) { + for (treatment in entryList) { + aapsLogger.debug(LTag.PUMP, "Add Bolus (no db entry): $treatment") + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: Add Bolus: FromDb=null, Treatment=$treatment") + addBolus(treatment, null) + } + } else { + for (treatment in entryList) { + val treatmentDb = findDbEntry(treatment, entriesFromHistory) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Add Bolus %s - (entryFromDb=%s) ", treatment, treatmentDb)) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: Add Bolus: FromDb=%s, Treatment=%s", treatmentDb, treatment)) + addBolus(treatment, treatmentDb as Treatment?) + } + } + } + + private fun filterOutNonInsulinEntries(entriesFromHistory: MutableList) { + // when we try to pair PumpHistory with AAPS treatments, we need to ignore all non-insulin entries + val removeList: MutableList = mutableListOf() + for (dbObjectBase in entriesFromHistory) { + val treatment = dbObjectBase as Treatment + if (Round.isSame(treatment.insulin, 0.0)) { + removeList.add(dbObjectBase) + } + } + entriesFromHistory.removeAll(removeList) + } + + private fun processTBREntries(entryList: MutableList) { + Collections.reverse(entryList) + val tbr = entryList[0].getDecodedDataEntry("Object") as TempBasalPair? + var readOldItem = false + if (tbr!!.isCancelTBR) { + val oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.TempBasalCombined) + if (oneMoreEntryFromHistory != null) { + entryList.add(0, oneMoreEntryFromHistory) + readOldItem = true + } else { + entryList.removeAt(0) + } + } + val oldestTimestamp = getOldestTimestamp(entryList) + val entriesFromHistory = getDatabaseEntriesByLastTimestamp(oldestTimestamp, ProcessHistoryRecord.TBR) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, ProcessHistoryRecord.TBR.description + " List (before filter): %s, FromDb=%s", gson.toJson(entryList), + gson.toJson(entriesFromHistory))) + var processDTO: TempBasalProcessDTO? = null + val processList: MutableList = ArrayList() + for (treatment in entryList) { + val tbr2 = treatment!!.getDecodedDataEntry("Object") as TempBasalPair? + if (tbr2!!.isCancelTBR) { + if (processDTO != null) { + processDTO.itemTwo = treatment + if (readOldItem) { + processDTO.processOperation = TempBasalProcessDTO.Operation.Edit + readOldItem = false + } + } else { + aapsLogger.error("processDTO was null - shouldn't happen. ItemTwo=$treatment") + } + } else { + if (processDTO != null) { + processList.add(processDTO) + } + processDTO = TempBasalProcessDTO() + processDTO.itemOne = treatment + processDTO.processOperation = TempBasalProcessDTO.Operation.Add + } + } + if (processDTO != null) { + processList.add(processDTO) + } + if (isCollectionNotEmpty(processList)) { + for (tempBasalProcessDTO in processList) { + if (tempBasalProcessDTO.processOperation === TempBasalProcessDTO.Operation.Edit) { + // edit + val tempBasal = findTempBasalWithPumpId(tempBasalProcessDTO.itemOne!!.pumpId!!, entriesFromHistory) + if (tempBasal != null) { + tempBasal.durationInMinutes = tempBasalProcessDTO.duration + databaseHelper.createOrUpdate(tempBasal) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Edit " + ProcessHistoryRecord.TBR.description + " - (entryFromDb=%s) ", tempBasal)) + } else { + aapsLogger.error(LTag.PUMP, "TempBasal not found. Item: " + tempBasalProcessDTO.itemOne) + } + } else { + // add + val treatment = tempBasalProcessDTO.itemOne + val tbr2 = treatment!!.decodedData!!["Object"] as TempBasalPair? + tbr2!!.durationMinutes = tempBasalProcessDTO.duration + val tempBasal = findTempBasalWithPumpId(tempBasalProcessDTO.itemOne!!.pumpId!!, entriesFromHistory) + if (tempBasal == null) { + val treatmentDb = findDbEntry(treatment, entriesFromHistory) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Add " + ProcessHistoryRecord.TBR.description + " %s - (entryFromDb=%s) ", treatment, treatmentDb)) + addTBR(treatment, treatmentDb as TemporaryBasal?) + } else { + // this shouldn't happen + if (tempBasal.durationInMinutes != tempBasalProcessDTO.duration) { + aapsLogger.debug(LTag.PUMP, "Found entry with wrong duration (shouldn't happen)... updating") + tempBasal.durationInMinutes = tempBasalProcessDTO.duration + } + } + } // if + } // for + } // collection + } + + private fun findTempBasalWithPumpId(pumpId: Long, entriesFromHistory: List): TemporaryBasal? { + for (dbObjectBase in entriesFromHistory) { + val tbr = dbObjectBase as TemporaryBasal + if (tbr.pumpId == pumpId) { + return tbr + } + } + return databaseHelper.findTempBasalByPumpId(pumpId) + } + + /** + * findDbEntry - finds Db entries in database, while theoretically this should have same dateTime they + * don't. Entry on pump is few seconds before treatment in AAPS, and on manual boluses on pump there + * is no treatment at all. For now we look fro tratment that was from 0s - 1m59s within pump entry. + * + * @param treatment Pump Entry + * @param entriesFromHistory entries from history + * @return DbObject from AAPS (if found) + */ + private fun findDbEntry(treatment: PumpHistoryEntry?, entriesFromHistory: List): DbObjectBase? { + val proposedTime = DateTimeUtil.toMillisFromATD(treatment!!.atechDateTime!!) + + //proposedTime += (this.pumpTime.timeDifference * 1000); + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Treatment=%s, FromDb=%s", treatment, gson.toJson(entriesFromHistory))) + if (entriesFromHistory.size == 0) { + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Treatment=%s, FromDb=null", treatment)) + return null + } else if (entriesFromHistory.size == 1) { + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Treatment=%s, FromDb=%s. Type=SingleEntry", treatment, entriesFromHistory[0])) + + // TODO: Fix db code + // if difference is bigger than 2 minutes we discard entry + val maxMillisAllowed = DateTimeUtil.getMillisFromATDWithAddedMinutes(treatment.atechDateTime!!, 2) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry maxMillisAllowed=%d, AtechDateTime=%d (add 2 minutes). ", maxMillisAllowed, treatment.atechDateTime)) + if (entriesFromHistory[0].getDate() > maxMillisAllowed) { + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: findDbEntry entry filtered out, returning null. ") + return null + } + return entriesFromHistory[0] + } + var min = 0 + while (min < 2) { + var sec = 0 + while (sec <= 50) { + if (min == 1 && sec == 50) { + sec = 59 + } + val diff = sec * 1000 + val outList: MutableList = ArrayList() + for (treatment1 in entriesFromHistory) { + if (treatment1.getDate() > proposedTime - diff && treatment1.getDate() < proposedTime + diff) { + outList.add(treatment1) + } + } + if (outList.size == 1) { + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Treatment={}, FromDb={}. Type=EntrySelected, AtTimeMin={}, AtTimeSec={}", treatment, entriesFromHistory[0], min, sec)) + return outList[0] + } + if (min == 0 && sec == 10 && outList.size > 1) { + aapsLogger.error(String.format(Locale.ENGLISH, "Too many entries (with too small diff): (timeDiff=[min=%d,sec=%d],count=%d,list=%s)", + min, sec, outList.size, gson.toJson(outList))) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: findDbEntry Error - Too many entries (with too small diff): (timeDiff=[min=%d,sec=%d],count=%d,list=%s)", + min, sec, outList.size, gson.toJson(outList))) + } + sec += 10 + } + min += 1 + } + return null + } + + private fun getDatabaseEntriesByLastTimestamp(startTimestamp: Long, processHistoryRecord: ProcessHistoryRecord): MutableList { + var outList: MutableList = mutableListOf() + + if (processHistoryRecord == ProcessHistoryRecord.Bolus) { + // TODO pumpSync + outList.addAll(activePlugin.activeTreatments.getTreatmentsFromHistoryAfterTimestamp(startTimestamp)) + } else { + // TODO pumpSync + outList.addAll(databaseHelper.getTemporaryBasalsDataFromTime(startTimestamp, true)) + } + + return outList + } + + private fun filterOutAlreadyAddedEntries(entryList: MutableList, treatmentsFromHistory: MutableList) { + if (isCollectionEmpty(treatmentsFromHistory)) + return + + val removeTreatmentsFromHistory: MutableList = ArrayList() + val removeTreatmentsFromPH: MutableList = ArrayList() + + for (treatment in treatmentsFromHistory) { + if (treatment.getPumpId() != 0L) { + var selectedBolus: PumpHistoryEntry? = null + for (bolus in entryList) { + if (bolus.pumpId == treatment.getPumpId()) { + selectedBolus = bolus + break + } + } + if (selectedBolus != null) { + entryList.remove(selectedBolus) + removeTreatmentsFromPH.add(selectedBolus) + removeTreatmentsFromHistory.add(treatment) + } + } + } + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: filterOutAlreadyAddedEntries: PumpHistory=%s, Treatments=%s", + gson.toJson(removeTreatmentsFromPH), + gsonCore.toJson(removeTreatmentsFromHistory))) + treatmentsFromHistory.removeAll(removeTreatmentsFromHistory) + } + + private fun addBolus(bolus: PumpHistoryEntry?, treatment: Treatment?) { + val bolusDTO = bolus!!.decodedData!!["Object"] as BolusDTO? + if (treatment == null) { + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): Bolus=$bolusDTO") + when (bolusDTO!!.bolusType) { + PumpBolusType.Normal -> { + val detailedBolusInfo = DetailedBolusInfo() + detailedBolusInfo.bolusTimestamp = tryToGetByLocalTime(bolus.atechDateTime!!) + detailedBolusInfo.pumpType = medtronicPumpStatus.pumpType + detailedBolusInfo.pumpSerial = medtronicPumpStatus.serialNumber + detailedBolusInfo.bolusPumpId = bolus.pumpId + detailedBolusInfo.insulin = bolusDTO.deliveredAmount!! + addCarbsFromEstimate(detailedBolusInfo, bolus) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): DetailedBolusInfo=$detailedBolusInfo") + // TODO pumpSync + val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) + bolus.linkedObject = detailedBolusInfo + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "addBolus - [date=%d,pumpId=%d, insulin=%.2f, newRecord=%b]", detailedBolusInfo.timestamp, + detailedBolusInfo.bolusPumpId, detailedBolusInfo.insulin, newRecord)) + } + + PumpBolusType.Audio, PumpBolusType.Extended -> { + val extendedBolus = ExtendedBolus(injector) + extendedBolus.date = tryToGetByLocalTime(bolus.atechDateTime!!) + extendedBolus.source = Source.PUMP + extendedBolus.insulin = bolusDTO.deliveredAmount!! + extendedBolus.pumpId = bolus.pumpId!! + extendedBolus.isValid = true + extendedBolus.durationInMinutes = bolusDTO.duration!! + bolus.linkedObject = extendedBolus + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): ExtendedBolus=$extendedBolus") + // TODO pumpSync + activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "addBolus - Extended [date=%d,pumpId=%d, insulin=%.3f, duration=%d]", extendedBolus.date, + extendedBolus.pumpId, extendedBolus.insulin, extendedBolus.durationInMinutes)) + } + } + } else { + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: addBolus(OldTreatment=%s): Bolus=%s", treatment, bolusDTO)) + treatment.source = Source.PUMP + treatment.pumpId = bolus.pumpId!! + treatment.insulin = bolusDTO!!.deliveredAmount!! + // TODO pumpSync + val updateReturn = activePlugin.activeTreatments.createOrUpdateMedtronic(treatment, false) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: addBolus(tretament!=null): NewTreatment=%s, UpdateReturn=%s", treatment, updateReturn)) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "editBolus - [date=%d,pumpId=%d, insulin=%.3f, newRecord=%s]", treatment.date, + treatment.pumpId, treatment.insulin, updateReturn.toString())) + bolus.linkedObject = treatment + } + } + + private fun addCarbsFromEstimate(detailedBolusInfo: DetailedBolusInfo, bolus: PumpHistoryEntry?) { + if (bolus!!.containsDecodedData("Estimate")) { + val bolusWizard = bolus.decodedData!!["Estimate"] as BolusWizardDTO? + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: addCarbsFromEstimate: Bolus=%s, BolusWizardDTO=%s", bolus, bolusWizard)) + detailedBolusInfo.carbs = bolusWizard!!.carbs.toDouble() + } + } + + private fun addTBR(treatment: PumpHistoryEntry?, temporaryBasalDbInput: TemporaryBasal?) { + val tbr = treatment!!.decodedData!!["Object"] as TempBasalPair? + var temporaryBasalDb = temporaryBasalDbInput + var operation = "editTBR" + if (temporaryBasalDb == null) { + temporaryBasalDb = TemporaryBasal(injector) + temporaryBasalDb.date = tryToGetByLocalTime(treatment.atechDateTime!!) + operation = "addTBR" + } + temporaryBasalDb.source = Source.PUMP + temporaryBasalDb.pumpId = treatment.pumpId!! + temporaryBasalDb.durationInMinutes = tbr!!.durationMinutes + temporaryBasalDb.absoluteRate = tbr.insulinRate + temporaryBasalDb.isAbsolute = !tbr.isPercent + treatment.linkedObject = temporaryBasalDb + databaseHelper.createOrUpdate(temporaryBasalDb) + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "$operation - [date=%d,pumpId=%d, rate=%s %s, duration=%d]", // + temporaryBasalDb.getDate(), // + temporaryBasalDb.getPumpId(), // + if (temporaryBasalDb.isAbsolute) String.format(Locale.ENGLISH, "%.2f", temporaryBasalDb.absoluteRate) else String.format(Locale.ENGLISH, "%d", temporaryBasalDb.percentRate), // + if (temporaryBasalDb.isAbsolute) "U/h" else "%", // + temporaryBasalDb.durationInMinutes)) + } + + private fun processSuspends(tempBasalProcessList: List) { + for (tempBasalProcess in tempBasalProcessList) { + var tempBasal = databaseHelper.findTempBasalByPumpId(tempBasalProcess.itemOne!!.pumpId!!) + if (tempBasal == null) { + // add + tempBasal = TemporaryBasal(injector) + tempBasal.date = tryToGetByLocalTime(tempBasalProcess.itemOne!!.atechDateTime!!) + tempBasal.source = Source.PUMP + tempBasal.pumpId = tempBasalProcess.itemOne!!.pumpId!! + tempBasal.durationInMinutes = tempBasalProcess.duration + tempBasal.absoluteRate = 0.0 + tempBasal.isAbsolute = true + tempBasalProcess.itemOne!!.linkedObject = tempBasal + tempBasalProcess.itemTwo!!.linkedObject = tempBasal + databaseHelper.createOrUpdate(tempBasal) + } + } + } + + // suspend/resume + // no_delivery/prime & rewind/prime + private fun getSuspendRecords(): MutableList { + val outList: MutableList = ArrayList() + + // suspend/resume + outList.addAll(getSuspendResumeRecordsList()) + // no_delivery/prime & rewind/prime + outList.addAll(getNoDeliveryRewindPrimeRecordsList()) + return outList + }// remove last and have paired items// remove last (unpaired R)// get one more from history (R S R) -> ([S] R S R)// remove last (unpaired R)// not full suspends, need to retrive one more record and discard first one (R S R S) -> ([S] R S R [xS])// full resume suspends (S R S R) + + // + // + private fun getSuspendResumeRecordsList(): List { + val filteredItems = getFilteredItems(newHistory, // + setOf(PumpHistoryEntryType.SuspendPump, PumpHistoryEntryType.ResumePump)) + val outList: MutableList = mutableListOf() + if (filteredItems.size > 0) { + val filtered2Items: MutableList = mutableListOf() + if (filteredItems.size % 2 == 0 && filteredItems[0].entryType === PumpHistoryEntryType.ResumePump) { + // full resume suspends (S R S R) + filtered2Items.addAll(filteredItems) + } else if (filteredItems.size % 2 == 0 && filteredItems[0].entryType === PumpHistoryEntryType.SuspendPump) { + // not full suspends, need to retrive one more record and discard first one (R S R S) -> ([S] R S R [xS]) + filteredItems.removeAt(0) + val oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.SuspendPump) + if (oneMoreEntryFromHistory != null) { + filteredItems.add(oneMoreEntryFromHistory) + } else { + filteredItems.removeAt(filteredItems.size - 1) // remove last (unpaired R) + } + filtered2Items.addAll(filteredItems) + } else { + if (filteredItems[0].entryType === PumpHistoryEntryType.ResumePump) { + // get one more from history (R S R) -> ([S] R S R) + val oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.SuspendPump) + if (oneMoreEntryFromHistory != null) { + filteredItems.add(oneMoreEntryFromHistory) + } else { + filteredItems.removeAt(filteredItems.size - 1) // remove last (unpaired R) + } + filtered2Items.addAll(filteredItems) + } else { + // remove last and have paired items + filteredItems.removeAt(0) + filtered2Items.addAll(filteredItems) + } + } + if (filtered2Items.size > 0) { + sort(filtered2Items) + Collections.reverse(filtered2Items) + var i = 0 + while (i < filtered2Items.size) { + val dto = TempBasalProcessDTO() + dto.itemOne = filtered2Items[i] + dto.itemTwo = filtered2Items[i + 1] + dto.processOperation = TempBasalProcessDTO.Operation.Add + outList.add(dto) + i += 2 + } + } + } + return outList + }////////// + + // + private fun getNoDeliveryRewindPrimeRecordsList(): List { + val primeItems: MutableList = getFilteredItems(newHistory, // + setOf(PumpHistoryEntryType.Prime)) + val outList: MutableList = ArrayList() + if (primeItems.size == 0) return outList + val filteredItems: MutableList = getFilteredItems(newHistory, // + setOf(PumpHistoryEntryType.Prime, + PumpHistoryEntryType.Rewind, + PumpHistoryEntryType.NoDeliveryAlarm, + PumpHistoryEntryType.Bolus, + PumpHistoryEntryType.TempBasalCombined) + ) + val tempData: MutableList = mutableListOf() + var startedItems = false + var finishedItems = false + for (filteredItem in filteredItems) { + if (filteredItem.entryType === PumpHistoryEntryType.Prime) { + startedItems = true + } + if (startedItems) { + if (filteredItem.entryType === PumpHistoryEntryType.Bolus || + filteredItem.entryType === PumpHistoryEntryType.TempBasalCombined) { + finishedItems = true + break + } + tempData.add(filteredItem) + } + } + if (!finishedItems) { + val filteredItemsOld: MutableList = getFilteredItems(allHistory, // + setOf(PumpHistoryEntryType.Rewind, + PumpHistoryEntryType.NoDeliveryAlarm, + PumpHistoryEntryType.Bolus, + PumpHistoryEntryType.TempBasalCombined) + ) + for (filteredItem in filteredItemsOld) { + if (filteredItem.entryType === PumpHistoryEntryType.Bolus || + filteredItem.entryType === PumpHistoryEntryType.TempBasalCombined) { + finishedItems = true + break + } + tempData.add(filteredItem) + } + } + if (!finishedItems) { + showLogs("NoDeliveryRewindPrimeRecords: Not finished Items: ", gson.toJson(tempData)) + return outList + } + showLogs("NoDeliveryRewindPrimeRecords: Records to evaluate: ", gson.toJson(tempData)) + var items: MutableList = getFilteredItems(tempData, PumpHistoryEntryType.Prime) + val processDTO = TempBasalProcessDTO() + processDTO.itemTwo = items[0] + items = getFilteredItems(tempData, PumpHistoryEntryType.NoDeliveryAlarm) + if (items.size > 0) { + processDTO.itemOne = items[items.size - 1] + processDTO.processOperation = TempBasalProcessDTO.Operation.Add + outList.add(processDTO) + return outList + } + items = getFilteredItems(tempData, PumpHistoryEntryType.Rewind) + if (items.size > 0) { + processDTO.itemOne = items[0] + processDTO.processOperation = TempBasalProcessDTO.Operation.Add + outList.add(processDTO) + return outList + } + return outList + } + + private fun getOneMoreEntryFromHistory(entryType: PumpHistoryEntryType): PumpHistoryEntry? { + val filteredItems: List = getFilteredItems(allHistory, entryType) + return if (filteredItems.size == 0) null else filteredItems[0] + } + + private fun filterTDDs(tdds: MutableList): MutableList { + val tddsOut: MutableList = mutableListOf() + for (tdd in tdds) { + if (tdd.entryType !== PumpHistoryEntryType.EndResultTotals) { + tddsOut.add(tdd) + } + } + return if (tddsOut.size == 0) tdds else tddsOut + } + + private fun findTDD(atechDateTime: Long, tddsDb: List): TDD? { + for (tdd in tddsDb) { + if (DateTimeUtil.isSameDayATDAndMillis(atechDateTime, tdd.date)) { + return tdd + } + } + return null + } + + private fun tryToGetByLocalTime(atechDateTime: Long): Long { + return DateTimeUtil.toMillisFromATD(atechDateTime) + } + +// private fun getOldestDateDifference(treatments: List): Int { +// var dt = Long.MAX_VALUE +// var currentTreatment: PumpHistoryEntry? = null +// if (isCollectionEmpty(treatments)) { +// return 8 // default return of 6 (5 for diif on history reading + 2 for max allowed difference) minutes +// } +// for (treatment in treatments) { +// if (treatment.atechDateTime!! < dt) { +// dt = treatment.atechDateTime!! +// currentTreatment = treatment +// } +// } +// var oldestEntryTime: LocalDateTime +// try { +// oldestEntryTime = DateTimeUtil.toLocalDateTime(dt) +// oldestEntryTime = oldestEntryTime.minusMinutes(3) +// +// // if (this.pumpTime.timeDifference < 0) { +// // oldestEntryTime = oldestEntryTime.plusSeconds(this.pumpTime.timeDifference); +// // } +// } catch (ex: Exception) { +// aapsLogger.error("Problem decoding date from last record: $currentTreatment") +// return 8 // default return of 6 minutes +// } +// val now = LocalDateTime() +// val minutes = Minutes.minutesBetween(oldestEntryTime, now) +// +// // returns oldest time in history, with calculated time difference between pump and phone, minus 5 minutes +// aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Oldest entry: %d, pumpTimeDifference=%d, newDt=%s, currentTime=%s, differenceMin=%d", dt, +// pumpTime!!.timeDifference, oldestEntryTime, now, minutes.minutes)) +// return minutes.minutes +// } + + private fun getOldestTimestamp(treatments: List): Long { + var dt = Long.MAX_VALUE + var currentTreatment: PumpHistoryEntry? = null + for (treatment in treatments) { + if (treatment!!.atechDateTime!! < dt) { + dt = treatment.atechDateTime!! + currentTreatment = treatment + } + } + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: getOldestTimestamp. Oldest entry found: time=%d, object=%s", dt, currentTreatment)) + return try { + val oldestEntryTime = DateTimeUtil.toGregorianCalendar(dt) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: getOldestTimestamp. oldestEntryTime: %s", DateTimeUtil.toString(oldestEntryTime))) + oldestEntryTime.add(Calendar.MINUTE, -2) + if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: getOldestTimestamp. oldestEntryTime (-2m): %s, timeInMillis=%d", DateTimeUtil.toString(oldestEntryTime), oldestEntryTime.timeInMillis)) + oldestEntryTime.timeInMillis + } catch (ex: Exception) { + aapsLogger.error("Problem decoding date from last record: $currentTreatment") + 8 // default return of 6 minutes + } + } + + private val tDDType: PumpHistoryEntryType + get() = if (medtronicUtil.medtronicPumpModel == null) { + PumpHistoryEntryType.EndResultTotals + } else when (medtronicUtil.medtronicPumpModel) { + MedtronicDeviceType.Medtronic_515, MedtronicDeviceType.Medtronic_715 -> PumpHistoryEntryType.DailyTotals515 + MedtronicDeviceType.Medtronic_522, MedtronicDeviceType.Medtronic_722 -> PumpHistoryEntryType.DailyTotals522 + MedtronicDeviceType.Medtronic_523_Revel, + MedtronicDeviceType.Medtronic_723_Revel, + MedtronicDeviceType.Medtronic_554_Veo, + MedtronicDeviceType.Medtronic_754_Veo -> PumpHistoryEntryType.DailyTotals523 + else -> { + PumpHistoryEntryType.EndResultTotals + } + } + + fun hasBasalProfileChanged(): Boolean { + val filteredItems: List = getFilteredItems(PumpHistoryEntryType.ChangeBasalProfile_NewProfile) + aapsLogger.debug(LTag.PUMP, "hasBasalProfileChanged. Items: " + gson.toJson(filteredItems)) + return filteredItems.size > 0 + } + + fun processLastBasalProfileChange(pumpType: PumpType?, mdtPumpStatus: MedtronicPumpStatus) { + val filteredItems: List = getFilteredItems(PumpHistoryEntryType.ChangeBasalProfile_NewProfile) + aapsLogger.debug(LTag.PUMP, "processLastBasalProfileChange. Items: $filteredItems") + var newProfile: PumpHistoryEntry? = null + var lastDate: Long? = null + if (filteredItems.size == 1) { + newProfile = filteredItems[0] + } else if (filteredItems.size > 1) { + for (filteredItem in filteredItems) { + if (lastDate == null || lastDate < filteredItem!!.atechDateTime!!) { + newProfile = filteredItem + lastDate = newProfile!!.atechDateTime + } + } + } + if (newProfile != null) { + aapsLogger.debug(LTag.PUMP, "processLastBasalProfileChange. item found, setting new basalProfileLocally: $newProfile") + val basalProfile = newProfile.decodedData!!["Object"] as BasalProfile? + mdtPumpStatus.basalsByHour = basalProfile!!.getProfilesByHour(pumpType!!) + } + } + + fun hasPumpTimeChanged(): Boolean { + return getStateFromFilteredList(setOf(PumpHistoryEntryType.NewTimeSet, // + PumpHistoryEntryType.ChangeTime)) + } + + // fun setLastHistoryRecordTime(lastHistoryRecordTime: Long?) { + // // this.previousLastHistoryRecordTime = this.lastHistoryRecordTime; + // } + + fun setIsInInit(init: Boolean) { + isInit = init + } + + // HELPER METHODS + private fun sort(list: MutableList) { + // if (list != null && !list.isEmpty()) { + // Collections.sort(list, PumpHistoryEntry.Comparator()) + // } + list.sortWith(PumpHistoryEntry.Comparator()) + } + + private fun preProcessTBRs(TBRs_Input: MutableList): MutableList { + val TBRs: MutableList = mutableListOf() + val map: MutableMap = HashMap() + for (pumpHistoryEntry in TBRs_Input) { + if (map.containsKey(pumpHistoryEntry.DT)) { + medtronicPumpHistoryDecoder.decodeTempBasal(map[pumpHistoryEntry.DT]!!, pumpHistoryEntry) + pumpHistoryEntry.setEntryType(medtronicUtil.medtronicPumpModel!!, PumpHistoryEntryType.TempBasalCombined) + TBRs.add(pumpHistoryEntry) + map.remove(pumpHistoryEntry.DT) + } else { + map[pumpHistoryEntry.DT] = pumpHistoryEntry + } + } + return TBRs + } + + private fun getFilteredItems(entryTypes: Set?): MutableList { + return getFilteredItems(newHistory, entryTypes) + } + + private fun getFilteredItems(entryType: PumpHistoryEntryType): MutableList { + return getFilteredItems(newHistory, setOf(entryType)) + } + + private fun getStateFromFilteredList(entryTypes: Set?): Boolean { + return if (isInit) { + false + } else { + val filteredItems: List = getFilteredItems(entryTypes) + aapsLogger.debug(LTag.PUMP, "Items: $filteredItems") + filteredItems.size > 0 + } + } + + private fun getFilteredItems(inList: MutableList?, entryType: PumpHistoryEntryType): MutableList { + return getFilteredItems(inList, setOf(entryType)) + } + + private fun getFilteredItems(inList: MutableList?, entryTypes: Set?): MutableList { + + // aapsLogger.debug(LTag.PUMP, "InList: " + inList.size()); + val outList: MutableList = mutableListOf() + if (inList != null && inList.size > 0) { + for (pumpHistoryEntry in inList) { + if (!isEmpty(entryTypes)) { + if (entryTypes!!.contains(pumpHistoryEntry.entryType)) { + outList.add(pumpHistoryEntry) + } + } else { + outList.add(pumpHistoryEntry) + } + } + } + + // aapsLogger.debug(LTag.PUMP, "OutList: " + outList.size()); + return outList + } + + private fun isEmpty(entryTypes: Set?): Boolean { + return entryTypes.isNullOrEmpty() + //return entryTypes == null || entryTypes.size == 1 && entryTypes[0] == null + } + + private val logPrefix: String + get() = "MedtronicHistoryData::" + + companion object { + /** + * Double bolus debug. We seem to have small problem with double Boluses (or sometimes also missing boluses + * from history. This flag turns on debugging for that (default is off=false)... Debugging is pretty detailed, + * so log files will get bigger. + * Note: June 2020. Since this seems to be fixed, I am disabling this per default. I will leave code inside + * in case we need it again. Code that turns this on is commented out RileyLinkMedtronicService#verifyConfiguration() + */ + const val doubleBolusDebug = false + } + + init { + //allHistory = ArrayList() + //this.injector = injector + //this.aapsLogger = aapsLogger + // this.sp = sp + // this.activePlugin = activePlugin + // this.medtronicUtil = medtronicUtil + // this.medtronicPumpHistoryDecoder = medtronicPumpHistoryDecoder + // this.medtronicPumpStatus = medtronicPumpStatus + // databaseHelper = databaseHelperInterface + //this.pumpSync = pumpSync + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt index b1af19654a..0d4d896fab 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt @@ -54,10 +54,10 @@ class BasalProfile { private fun setRawData(data: ByteArray): Boolean { var dataInternal: ByteArray = data - if (dataInternal == null) { - aapsLogger.error(LTag.PUMPCOMM, "setRawData: buffer is null!") - return false - } + // if (dataInternal == null) { + // aapsLogger.error(LTag.PUMPCOMM, "setRawData: buffer is null!") + // return false + // } // if we have just one entry through all day it looks like just length 1 if (dataInternal.size == 1) { @@ -219,7 +219,7 @@ class BasalProfile { fun generateRawDataFromEntries() { val outData: MutableList = ArrayList() for (profileEntry in listEntries!!) { - val strokes = MedtronicUtil.getBasalStrokes(profileEntry.rate, true) + //val strokes = MedtronicUtil.getBasalStrokes(profileEntry.rate, true) outData.add(profileEntry.rate_raw[0]) outData.add(profileEntry.rate_raw[1]) outData.add(profileEntry.startTime_raw) @@ -238,17 +238,17 @@ class BasalProfile { aapsLogger.error(LTag.PUMPCOMM, " Error generating entries. Ex.: $ex", ex) aapsLogger.error(LTag.PUMPCOMM, " rawBasalValues: " + ByteUtil.shortHexString(rawData)) aapsLogger.error(LTag.PUMPCOMM, "=============================================================================") - //FabricUtil.createEvent("MedtronicBasalProfileGetByHourError", null); } + + val basalByHour = arrayOf() + if (entriesCopy == null || entriesCopy.size == 0) { - val basalByHour = arrayOfNulls(24) for (i in 0..23) { basalByHour[i] = 0.0 } - return basalByHour as Array + return basalByHour } - val basalByHour = arrayOfNulls(24) for (i in entriesCopy.indices) { val current = entriesCopy[i] var currentTime = if (current.startTime_raw % 2 == 0) current.startTime_raw.toInt() else current.startTime_raw - 1 @@ -264,13 +264,13 @@ class BasalProfile { // System.out.println("Current time: " + currentTime + " Next Time: " + lastHour); for (j in currentTime until lastHour) { - if (pumpType == null) - basalByHour[j] = current.rate - else + // if (pumpType == null) + // basalByHour[j] = current.rate + // else basalByHour[j] = pumpType.determineCorrectBasalSize(current.rate) } } - return basalByHour as Array + return basalByHour } override fun toString(): String { @@ -285,7 +285,7 @@ class BasalProfile { } val profilesByHour = getProfilesByHour(pumpType) for (aDouble in profilesByHour) { - if (aDouble!! > 35.0) return false + if (aDouble > 35.0) return false } return true } @@ -296,7 +296,6 @@ class BasalProfile { const val MAX_RAW_DATA_SIZE = 48 * 3 + 1 private const val DEBUG_BASALPROFILE = false - // this asUINT8 should be combined with Record.asUINT8, and placed in a new util class. private fun readUnsignedByte(b: Byte): Int { return if (b < 0) b + 256 else b.toInt() } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.kt index 47d4f4f1ba..f419c7f56c 100755 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.kt @@ -4,9 +4,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.R import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.MessageBody import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.PumpAckMessageBody import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.UnknownMessageBody -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType.Companion.isSameDevice -import java.io.Serializable import java.util.* /** @@ -136,35 +134,14 @@ enum class MedtronicCommandType companion object { var mapByCode: MutableMap = HashMap() - private fun getDeviceTypesArray(vararg types: MedtronicDeviceType): HashMap { - val hashMap = HashMap() - for (type in types) { - hashMap[type] = null - } - return hashMap - } - - // @JvmStatic - // fun getByteArray(vararg data: Int): ByteArray { - // val array = ByteArray(data.size) - // for (i in 0 until data.size) { - // array[i] = data[i].toByte() + // private fun getDeviceTypesArray(vararg types: MedtronicDeviceType): HashMap { + // val hashMap = HashMap() + // for (type in types) { + // hashMap[type] = null // } - // return array + // return hashMap // } - // private fun getByteArray(vararg data: Int): ByteArray { - // val array = ByteArray(data.size) - // for (i in 0 until data.size) { - // array[i] = data[i].toByte() - // } - // return array - // } - - private fun getIntArray(vararg data: Int): IntArray { - return data - } - fun getByCode(code: Byte): MedtronicCommandType? { return if (mapByCode.containsKey(code)) { mapByCode[code] @@ -203,7 +180,6 @@ enum class MedtronicCommandType var maxRecords = 1 var resourceId: Int? = null private set - var command_type = 0 var allowedRetries = 2 var maxAllowedTime = 2000 var parameterType: MinimedCommandParameterType? = null @@ -217,7 +193,7 @@ enum class MedtronicCommandType } constructor(code: Int, description: String, devices: MedtronicDeviceType?, - parameterType: MinimedCommandParameterType?, cmd_params: ByteArray) : this(code, description, devices, parameterType, 0, 1, 0, 0, 11, 0) { + parameterType: MinimedCommandParameterType?, cmd_params: ByteArray) : this(code, description, devices, parameterType) { commandParameters = cmd_params commandParametersCount = cmd_params.size } @@ -233,10 +209,14 @@ enum class MedtronicCommandType } // NEW - constructor(code: Int, description: String, - devices: MedtronicDeviceType?, // - parameterType: MinimedCommandParameterType?, recordLength: Int = 64, max_recs: Int = 1, expectedLength: Int = 0, - resourceId: Int? = null) { + constructor(code: Int, + description: String, + devices: MedtronicDeviceType?, // + parameterType: MinimedCommandParameterType?, + recordLength: Int = 64, + max_recs: Int = 1, + expectedLength: Int = 0, + resourceId: Int? = null) { commandCode = code.toByte() commandDescription = description this.devices = devices @@ -252,25 +232,25 @@ enum class MedtronicCommandType } } - @Deprecated("") - constructor(code: Int, description: String, devices: MedtronicDeviceType?, // - parameterType: MinimedCommandParameterType?, recordLength: Int, max_recs: Int, addy: Int, // - addy_len: Int, cmd_type: Int, expectedLength: Int) { - commandCode = code.toByte() - commandDescription = description - //this.targetType = targetType; - this.devices = devices - this.recordLength = recordLength - maxRecords = max_recs - command_type = cmd_type - commandParametersCount = 0 - allowedRetries = 2 - this.parameterType = parameterType - this.expectedLength = expectedLength - if (this.parameterType == MinimedCommandParameterType.SubCommands) { - minimalBufferSizeToStartReading = 200 - } - } + // @Deprecated("") + // constructor(code: Int, description: String, devices: MedtronicDeviceType?, // + // parameterType: MinimedCommandParameterType?, recordLength: Int, max_recs: Int, addy: Int, // + // addy_len: Int, cmd_type: Int, expectedLength: Int) { + // commandCode = code.toByte() + // commandDescription = description + // //this.targetType = targetType; + // this.devices = devices + // this.recordLength = recordLength + // maxRecords = max_recs + // command_type = cmd_type + // commandParametersCount = 0 + // allowedRetries = 2 + // this.parameterType = parameterType + // this.expectedLength = expectedLength + // if (this.parameterType == MinimedCommandParameterType.SubCommands) { + // minimalBufferSizeToStartReading = 200 + // } + // } override fun toString(): String { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.kt index 6f4cf7704c..6f8be29bd6 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.kt @@ -16,28 +16,28 @@ enum class MedtronicDeviceType { Medtronic_511("511"), // Medtronic_512("512"), // Medtronic_712("712"), // - Medtronic_512_712(Medtronic_512, Medtronic_712), // + Medtronic_512_712(listOf(Medtronic_512, Medtronic_712)), // Medtronic_515("515"), // Medtronic_715("715"), // - Medtronic_515_715(Medtronic_515, Medtronic_715), // + Medtronic_515_715(listOf(Medtronic_515, Medtronic_715)), // Medtronic_522("522"), // Medtronic_722("722"), // - Medtronic_522_722(Medtronic_522, Medtronic_722), // + Medtronic_522_722(listOf(Medtronic_522, Medtronic_722)), // Medtronic_523_Revel("523"), // Medtronic_723_Revel("723"), // Medtronic_554_Veo("554"), // Medtronic_754_Veo("754"), // - Medtronic_512andHigher(Medtronic_512, Medtronic_712, Medtronic_515, Medtronic_715, Medtronic_522, Medtronic_722, Medtronic_523_Revel, Medtronic_723_Revel, Medtronic_554_Veo, Medtronic_754_Veo), // - Medtronic_515andHigher(Medtronic_515, Medtronic_715, Medtronic_522, Medtronic_722, Medtronic_523_Revel, Medtronic_723_Revel, Medtronic_554_Veo, Medtronic_754_Veo), // - Medtronic_522andHigher(Medtronic_522, Medtronic_722, Medtronic_523_Revel, Medtronic_723_Revel, Medtronic_554_Veo, Medtronic_754_Veo), // - Medtronic_523andHigher(Medtronic_523_Revel, Medtronic_723_Revel, Medtronic_554_Veo, Medtronic_754_Veo), // - Medtronic_554andHigher(Medtronic_554_Veo, Medtronic_754_Veo), // + Medtronic_512andHigher(listOf(Medtronic_512, Medtronic_712, Medtronic_515, Medtronic_715, Medtronic_522, Medtronic_722, Medtronic_523_Revel, Medtronic_723_Revel, Medtronic_554_Veo, Medtronic_754_Veo)), // + Medtronic_515andHigher(listOf(Medtronic_515, Medtronic_715, Medtronic_522, Medtronic_722, Medtronic_523_Revel, Medtronic_723_Revel, Medtronic_554_Veo, Medtronic_754_Veo)), // + Medtronic_522andHigher(listOf(Medtronic_522, Medtronic_722, Medtronic_523_Revel, Medtronic_723_Revel, Medtronic_554_Veo, Medtronic_754_Veo)), // + Medtronic_523andHigher(listOf(Medtronic_523_Revel, Medtronic_723_Revel, Medtronic_554_Veo, Medtronic_754_Veo)), // + Medtronic_554andHigher(listOf(Medtronic_554_Veo, Medtronic_754_Veo)), // // All; companion object { - var mapByDescription: MutableMap? = null + var mapByDescription: MutableMap = mutableMapOf() @JvmStatic fun isSameDevice(deviceWeCheck: MedtronicDeviceType, deviceSources: MedtronicDeviceType): Boolean { @@ -52,20 +52,17 @@ enum class MedtronicDeviceType { } fun getByDescription(desc: String): MedtronicDeviceType { - return if (mapByDescription==null) { - Unknown_Device - } else if (mapByDescription!!.containsKey(desc)) { - mapByDescription!![desc]!! + return if (mapByDescription.containsKey(desc)) { + mapByDescription[desc]!! } else { Unknown_Device } } init { - mapByDescription = HashMap() for (minimedDeviceType in values()) { - if (!minimedDeviceType.isFamily) { - mapByDescription!![minimedDeviceType.pumpModel!!] = minimedDeviceType + if (!minimedDeviceType.isFamily && minimedDeviceType.pumpModel!=null) { + mapByDescription[minimedDeviceType.pumpModel!!] = minimedDeviceType } } } @@ -78,16 +75,20 @@ enum class MedtronicDeviceType { // return isSameDevice(model, Medtronic_523andHigher); // } val isFamily: Boolean - var familyMembers: Array? = null + var familyMembers: List? = null private set + constructor() { + isFamily = false + } + constructor(pumpModel: String?) { isFamily = false this.pumpModel = pumpModel } - constructor(vararg familyMembers: MedtronicDeviceType) { - this.familyMembers = familyMembers as Array? + constructor(familyMembers: List) { + this.familyMembers = familyMembers isFamily = true } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/di/MedtronicModule.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/di/MedtronicModule.kt index 5e9958fee9..30bbf1681d 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/di/MedtronicModule.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/di/MedtronicModule.kt @@ -6,6 +6,7 @@ import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicFragment import info.nightscout.androidaps.plugins.pump.medtronic.comm.MedtronicCommunicationManager +import info.nightscout.androidaps.plugins.pump.medtronic.comm.ui.MedtronicUIComm import info.nightscout.androidaps.plugins.pump.medtronic.comm.ui.MedtronicUITask import info.nightscout.androidaps.plugins.pump.medtronic.dialog.MedtronicHistoryActivity import info.nightscout.androidaps.plugins.pump.medtronic.dialog.RileyLinkStatusDeviceMedtronic @@ -22,6 +23,8 @@ abstract class MedtronicModule { @ContributesAndroidInjector abstract fun medtronicCommunicationManagerProvider(): MedtronicCommunicationManager @ContributesAndroidInjector abstract fun medtronicUITaskProvider(): MedtronicUITask @ContributesAndroidInjector abstract fun contributesRileyLinkStatusDeviceMedtronic(): RileyLinkStatusDeviceMedtronic + @ContributesAndroidInjector abstract fun medtronicUICommProvider(): MedtronicUIComm + companion object { @Provides diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt index d8fb29c42a..1310b483b5 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt @@ -17,9 +17,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin import info.nightscout.androidaps.plugins.pump.medtronic.R import info.nightscout.androidaps.plugins.pump.medtronic.comm.MedtronicCommunicationManager import info.nightscout.androidaps.plugins.pump.medtronic.comm.ui.MedtronicUIComm -import info.nightscout.androidaps.plugins.pump.medtronic.comm.ui.MedtronicUIPostprocessor import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus -import info.nightscout.androidaps.plugins.pump.medtronic.service.RileyLinkMedtronicService import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil import javax.inject.Inject @@ -34,13 +32,11 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi @Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin @Inject lateinit var medtronicUtil: MedtronicUtil - @Inject lateinit var medtronicUIPostprocessor: MedtronicUIPostprocessor @Inject lateinit var medtronicPumpStatus: MedtronicPumpStatus @Inject lateinit var rfSpy: RFSpy @Inject lateinit var medtronicCommunicationManager: MedtronicCommunicationManager + @Inject lateinit var medtronicUIComm: MedtronicUIComm - var medtronicUIComm: MedtronicUIComm? = null - private set private val mBinder: IBinder = LocalBinder() private var serialChanged = false private var frequencies: Array? = null @@ -82,7 +78,6 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi rileyLinkServiceData.rileyLinkAddress = sp.getString(RileyLinkConst.Prefs.RileyLinkAddress, "") rileyLinkServiceData.rileyLinkName = sp.getString(RileyLinkConst.Prefs.RileyLinkName, "") rfspy.startReader() - medtronicUIComm = MedtronicUIComm(injector, aapsLogger, medtronicUtil, medtronicUIPostprocessor, medtronicCommunicationManager) aapsLogger.debug(LTag.PUMPCOMM, "RileyLinkMedtronicService newly constructed") }